【学习笔记】xml&反射

为了灵活实现不一样路径执行不一样的资源,咱们须要使用xml进行配置;为了限定xml内容,须要使用xml约束(dtd或schema);为了获取xml内容,须要使用dom4j进行解析。html

1.xml定义

xml全称是Extensible Markup Language,意思是可扩展的标记语言。xml语法和html类似,但html的元素是固定的,xml的标签能够自定义。java

2.xml约束

2.1 DTD约束
DTD(Document Type Definition):文档类型定义,用于约束xml文档,规定xml文档中元素的名称,子元素的名称和顺序,元素属性等。web

2.2 schema约束
schema是新的xml文档约束,比DTD强大不少,是DTD的替代者。schema自己也是xml文档,但扩展名是sxd。
schema支持命名空间,用于处理元素和属性的名称冲突问题。编程

约束引入能够是本地引入SYSTEM和网络引入PUBLICapi

3.xml解析

常见的xml解析方式有三种:浏览器

解析器:就是根据不一样的解析方式提供不一样的具体实现。网络

(1)DOM:要求解析器把整个xml文档装载到内存,并解析成一个Document对象
优势:元素之间保留结构关系,能够进行增删改查操做
缺点:xml文档过大时可能出现内存溢出。app

(2)SAX:是一种高速,高效率的方法。它逐行扫描文档,一边扫描一边解析,并以事件驱动的方式进行具体解析,每执行一行,就触发对应的事件。解析器SaxReader对象。
优势:速度快,能够处理大文件
缺点:只能读,读完一行后将释放资源。dom

(3)PULL:Android内置的xml解析方式,相似SAXjvm

常见的解析开发包:
JAXP:sun公司提供支持DOM和SAX开发包
JDOM:dom4j的兄弟
jsoup:一种处理html特定解析开发包
dom4j:经常使用的解析开发包

4.SAX解析之解析包dom4j的使用

若是要使用dom4j,必须导入jar包。dom4j必须使用核心类SaxReader加载xml文档获取Document,经过Document对象得到文档的根元素(web-app),而后就能够操做了。示例代码:

package com.xing.xml;

import java.util.List;
//dom4j的使用
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.jupiter.api.Test;

public class test {
    @Test
    public void test001() {
        try {
            //1.获取Document
            SAXReader saxReader=new SAXReader();
            Document document;
            document = saxReader.read("src/com/xing/xml/web.xml");
            //2.得到根元素
            Element rootElement=document.getRootElement();
            System.out.println("根元素:"+rootElement);
            System.out.println("根元素的version属性:"+rootElement.attributeValue("version"));//获取version属性
            //3.得到根元素的子标签,Servlet,Servlet-Mapping
            List<Element> AllChildElements = rootElement.elements();
            System.out.println("根元素的全部子标签:"+AllChildElements);
            //遍历全部子标签
            for (Element childElement : AllChildElements) {
                //4.处理servlet,并获取子标签的内容如servlet-name
                if("servlet".equals(childElement.getName())) {
                    //方式一:得到元素对象,而后获取文本
                    System.out.println("方式一获取标签servlet-name内容:"+childElement.element("servlet-name").getText());
                    //方式二:获取元素文本值
                    System.out.println("方式二获取标签servlet-class内容"+childElement.elementText("servlet-class"));
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}

5.反射

a.什么是反射技术?

动态获取指定类以及类中的内容,并运行其内容。

应用程序已经运行,没法在其中进行new对象的创建,就没法使用对象。这时能够根据配置文件的类全名去找对应的字节码文件(类编译后的.class文件),并加载进内存,并建立该类对象实例。这就须要使用反射技术完成。

b.获取Class对象的三种方式

tips:类对象指类的Class对象,也就是字节码对象。能够经过Class.forName()/getclass()/.class来获取,当jvm加载一个类时就会为这个类建立一个Class对象;
类的对象,一般就是指经过new这个类或者反射获得Class对象再调用newInstance()建立的对象,存在内存的堆中,也叫类的实例

方式一:建立该类的对象,再调用getClass方法完成。
Person p = new Person();
Class clazz = p.getClass();//经过object继承来的方法(getClass)获取Person对应的字节码文件对象

方式二:每个类都具有一个class静态属性,经过该属性便可获取该类的字节码文件对象。但仍是有一点不方便,还必需要使用到该类。

Class clazz = Person.class;

获取Class对象方式三: Class.forName(className)方法:
相对方便,不须要直接使用具体的类,只要知道该类的名字便可。而名字彻底能够做为参数进行传递 ,这样就能够提升扩展性。所以为了动态获取一个类,第三种方式最为经常使用。
Class clazz = Class.forName("className");//必须类全名

c.建立类的对象的方式

之前:先加载Person类进内存,将该类封装成Class对象。根据Class对象,用new操做符建立Person对象,调用构造函数对该对象进行初始化。Person p = new Person();
经过上面的方式三:
(反射的关键)
根据名称获取其对应的字节码文件对象:
1.根据指定的类名称,经过forName()去查找对应的字节码文件,并加载进内存.
2.将该字节码文件封装成Class对象(类对象)。
3.直接经过newIntstance方法,完成该对象的建立(类的对象)。
如:
String className = "Person";
Class clazz = Class.forName(className);
Object object = clazz.newInstance();

反射代码示例:

package com.xing.testMap;

public interface MyServlet {
 public void testMyServlet();
}
package com.xing.testMap;

public class MyServletImpl implements MyServlet{

    @Override
    public void testMyServlet() {
        System.out.println("hello,test");
    }

}
package com.xing.testMap;

import org.junit.Test;

/**
 * 若是直接使用new MyServletImpl(),这种编程方式称之为硬编码,即代码写死了
 * 为了程序后期的可扩展性,使用反射较为合适
 * @author Xing
 *
 */
public class test{
    @Test
    public void test() throws Exception {
        //1.Class.forName()返回指定接口或类的对象。(实现类)
        //2.newInstance()经过class对象建立类的实例对象,至关于new xxx
        Class clazz=Class.forName("com.xing.testMap.MyServletImpl");
        MyServlet myservlet=(MyServlet) clazz.newInstance();//须要强转
        //执行
        myservlet.testMyServlet();
    }
    
}

以上程序使用反射能够建立对象的实例,但使用的是全限定类名,程序仍然是写死的,接下来咱们将经过读取xml文件的类名(servlet-class)来优化Class.forName("com.xing.testMap.MyServletImpl")

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app SYSTEM "web-app_2_3.dtd">
<web-app version="4.0">
    <servlet>
        <servlet-name>helloMyservlet</servlet-name>
        <servlet-class>com.xing.testMapAndXml.MyServletImpl</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloMyservlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>
package com.xing.testMapAndXml;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
//MyServlet.java,MyServletImpl.java和上面的同样
public class test {
    @Test
    public void test() {
        try {
            //加载xml文件
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read("src/com/xing/testMapAndXml/web.xml");
            //获取第一个子标签servlet
            Element element = document.getRootElement().element("servlet");
            String servletElement = element.elementText("servlet-class");//读取xml文件里的类名
            MyServlet myserlet=(MyServlet) Class.forName(servletElement).newInstance();
            myserlet.testMyServlet();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

 

模拟浏览器路径:
上面咱们已经解析了xml文件,不过得到的内容是固定的,咱们但愿若是用户访问的路径是/hello,将执行MyServlet程序,若是访问/hello2,将执行MyServlet2程序。

代码示例(接口和实现类省略了):读取xml文件后,把url-pattern和servlet-class组成键值对,调用时使用不一样的key获取不一样的类全名来建立对象,执行对象的方法。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://www.example.org/web-app_2_5" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
            version="2.5">
    <servlet>
        <servlet-name>helloMyservlet</servlet-name>
        <servlet-class>com.xing.testXmlAndBrowser.MyServletImpl</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloMyservlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>helloMyservlet2</servlet-name>
        <servlet-class>com.xing.testXmlAndBrowser.MyServletImpl2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloMyservlet2</servlet-name>
        <url-pattern>/hello2</url-pattern>
    </servlet-mapping>
</web-app>
package com.xing.testXmlAndBrowser;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Before;
import org.junit.Test;

public class test {
    
    //key:请求路径,value:实现类
    private Map<String, String> data=new HashMap<String,String>();
    @Before
    public void getMap() {
        try {
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read("src/com/xing/testXmlAndBrowser/web.xml");
            //得到全部子元素
            List<Element> AllChildElements = document.getRootElement().elements();
            //遍历全部子元素,1.解析到servlet,将其子标签servlet-name,servlet-class存放在Map中.
            //2.解析到servlet-mapping,得到子标签servlet-name,url-pattern,从Map中得到1的内容,组合成url=class键值对
            for (Element childElement : AllChildElements){
                if("servlet".equals(childElement.getName())) {
                    String servletName = childElement.elementText("servlet-name");
                    String servletClass = childElement.elementText("servlet-class");
                    data.put(servletName,servletClass);
                }
                //若是是servlet-mapping,得到其内容,组成键值对存放于Map中
                if("servlet-mapping".equals(childElement.getName())) {
                    String servletName=childElement.elementText("servlet-name");
                    String urlPattern=childElement.elementText("url-pattern");
                    //得到servlet-name以前存放在Map中的servlet-class值.与urlPattern组成键值对
                    String servletClass = data.get(servletName);
                    data.put(urlPattern,servletClass);
                    //将以前存放的数据删除.Map(urlPattern,classImpl)
                    data.remove(servletName);
                }
            }
//            System.out.println(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    
    @Test
    public void test() throws Exception {
        String key = "/hello";
        String key2 = "/hello2";
        MyServlet myServlet = (MyServlet) Class.forName(data.get(key)).newInstance();
        MyServlet2 myServlet2 = (MyServlet2) Class.forName(data.get(key2)).newInstance();
        myServlet.testMyServlet();
        myServlet2.testMyServlet2();
    }
}
相关文章
相关标签/搜索