【學習筆記】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();
    }
}
相關文章
相關標籤/搜索