XML&反射

1、學習目標
使用反射模擬servlet執行。
能夠編寫xml存聽任意內容
經過DTD約束編寫指定格式的XML
經過Schema約束編寫指定格式的XML
可使用D0M4解析XML
會使用反射對類、方法、構造進行相應操做
 
2、相關技術
    爲了靈活實現不一樣路徑(/hello)執行不一樣的資源(HelloMyServlet)咱們須要使用XML進行配置;爲了限定XML內容,咱們須要使用XML約束(DTD或schema);爲了得到xml的內容,咱們須要使用dom4j
進行解析。
 
什麼是XML?
    XML全稱是Extensible Markup Language,意思是能夠擴展的標記語言。XML標籤是能夠由用戶自定義的。(用於配置文件)
 
XML的做用?
一、配置文件( 主要
二、存放數據(傳輸數據)
 
XML語法?
一、XML文檔聲明
<?xml  version="1.0" encoding="UTF-8">
a、文檔聲明必須爲<?xml 開頭,以?>結束
b、文檔聲明必須從文檔的0行0列位置開始
c、文檔只有三個屬性     version   encoding
二、元素element
三、屬性
四、註釋
五、轉義字符
六、CDATA區
 
DTD約束?
        DTD(Document Type Definition),文檔類型定義,用來約束XML文檔。
DTD重點要求:不多本身編寫DTD約束文檔,都是經過框架提供的DTD約束文檔編寫對象的XML文檔。常見框架使用DTD約束有:struts二、hibernate等。
 
DTD文檔聲明
一、內部DTD,在CML文檔內部嵌入DTD,只對當前XML有限
二、外部DTD-本地DTD,DTD文檔在本地系統上,公司內部自動項目使用  關鍵字: SYSTEM
三、外部DTD-公共DTD,DTD文檔在網絡上,通常都由框架提供   關鍵字: PUBLIC
 
元素聲明?
定義元素語法:<!ELEMENT  元素名  元素描述>
元素名:自定義
元素描述:符號和數據類型
常見符號:
? :該對象能夠出現,但只能出現一次
*:任意次或零次
+ :最少出現一次
() :給元素分組
| :選擇一個
,:順序出現
常見類型:
#PCDATA表示內容是文本,不能是子標籤
 
約束文檔:
<?xml version="1.0" encoding="UTF-8"?>
<!--
       DTD教學實例文檔。
       模擬servlet2.3規範,若是開發人員須要在xml使用當前DTD約束,必須包括DOCTYPE。
       格式以下:
       <!DOCTYPE web-app SYSTEM "web-app_2_3.dtd">
-->
<!ELEMENT web-app (servlet*,servlet-mapping* , welcome-file-list?) >
<!ELEMENT servlet (servlet-name,description?,(servlet-class|jsp-file))>
<!ELEMENT servlet-mapping (servlet-name,url-pattern+) >
<!ELEMENT servlet-name (#PCDATA)>
<!ELEMENT servlet-class (#PCDATA)>
<!ELEMENT url-pattern (#PCDATA)>
<!ELEMENT description (#PCDATA)>
<!ELEMENT jsp-file (#PCDATA)>
 
<!ELEMENT welcome-file-list (welcome-file+)>
<!ELEMENT welcome-file (#PCDATA)>
 
<!ATTLIST web-app version CDATA #IMPLIED>
 
注:經過框架提供的DTD文檔,本身可以寫出xml文件。
 
Schema約束 ?  
Schema約束比DTD強大不少,是DTD的替代者。主要用於spring
重點要求:
經過schema約束文檔編寫xml文件。
 
<?xml version="1.0" encoding="UTF-8"?>
<!--
       Schema教學實例文檔。
       模擬servlet2.5規範,若是開發人員須要在xml使用當前Schema約束,必須包括指定命名空間。
       格式以下:
       <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">
-->
<xsd:schema xmlns=" http://www.w3.org/2001/XMLSchema";
       targetNamespace=" http://www.example.org/web-app_2_5";
       xmlns:xsd=" http://www.w3.org/2001/XMLSchema";
       xmlns:tns=" http://www.example.org/web-app_2_5";
       elementFormDefault="qualified">
       
       <xsd:element name="web-app">
             <xsd:complexType>
                    <xsd:choice minOccurs="0" maxOccurs="unbounded">
                           <xsd:element name="servlet">
                                 <xsd:complexType>
                                        <xsd:sequence>
                                               <xsd:element name="servlet-name"></xsd:element>
                                               <xsd:element name="servlet-class"></xsd:element>
                                        </xsd:sequence>
                                 </xsd:complexType>
                           </xsd:element>
                           <xsd:element name="servlet-mapping">
                                 <xsd:complexType>
                                        <xsd:sequence>
                                               <xsd:element name="servlet-name"></xsd:element>
                                               <xsd:element name="url-pattern" maxOccurs="unbounded"></xsd:element>
                                        </xsd:sequence>
                                 </xsd:complexType>
                           </xsd:element>
                           <xsd:element name="welcome-file-list">
                                 <xsd:complexType>
                                        <xsd:sequence>
                                               <xsd:element name="welcome-file" maxOccurs="unbounded"></xsd:element>
                                        </xsd:sequence>
                                 </xsd:complexType>
                           </xsd:element>
                    </xsd:choice>
                    <xsd:attribute name="version" type="double" use="optional"></xsd:attribute>
             </xsd:complexType>
       </xsd:element>
</xsd:schema>
 
dom4j 解析?
    當數據存儲在XML中,咱們就但願經過程序得到XML的內容。人們爲不一樣問題提供不一樣的解析方式,並提交對應的解析器,方便開發人員操做XML。
 
開發中比較常見的解析方式有三種:
一、DOM:java主要用的。
DOM將文檔一次性加載到內存造成樹形結構,進行解析。
優勢:方便對數形結構進行操做,能夠進行增、刪、改的操做。
缺點:若是文檔特別大,加載到內存中,容易致使內存溢出。
二、SAX:事件驅動方式,邊讀邊解析。
優勢:不會致使內存溢出。
缺點:不能增刪改操做。
三、PULL
 
常見的解析開發包:
JAXP:sun公司提供支持DOM和SAX開發包
JDom:dom4j兄弟
jsoup:一種處理HTML特定解析開發包
dom4j:比較經常使用的解析開發包,hibernate底層採用
 
API使用:
若是須要使用dom4j,必須導入jar包。
dom4j必須使用核心類SaxReader加載xml文檔得到Document,經過Document對象得到文檔的根元素,而後就能夠操做了。
常見API以下:
1.SaxReader對象    
   read(...):加載執行xml文檔
2.Document對象
getRootElement():得到根元素
3.Element對象
a、elements()  得到全部子元素
b、element()得到指定名稱第一個子元素
c、getName()得到當前元素的元素名
d、attributeValue()得到指定屬性名的屬性值
e、elementText()得到指定名稱子元素的文本值
f、getText()得到當前元素的文本內容
 
實現步驟(掌握):
一、導入jar包  :dom4j-1.6.1.jar
二、編寫web.xml
三、解析web.xml
 
web.xml
<?xml version="1.0" encoding="UTF-8"?>
                    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>helloServlet</servlet-name>
             <servlet-class>ct.FirstServlet</servlet-class>
       </servlet>
       
       <servlet-mapping>
             <servlet-name>helloServlet</servlet-name>
             <url-pattern>/test</url-pattern>
       </servlet-mapping>
       
       <welcome-file-list>
             <welcome-file>index.html</welcome-file>
       </welcome-file-list>
                    
</web-app>
 
 
package com.scalpel.xml.dom4j;
 
import java.util.List;
 
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
 
public class TestDom4j {
       
       @Test
       public void testReadWebXML()
       {
             try {
             //1.得到解析器
             SAXReader saxReader = new SAXReader();
             //2.得到document文檔對象          
             Document doc = saxReader.read("src/com/scalpel/schema/web.xml");
             //3.得到根元素
             Element rootElement = doc.getRootElement();
             System.out.println(rootElement.getName());//獲取根元素名稱
             System.out.println(rootElement.attributeValue("version"));//獲取根元素的屬性值
             //4.獲取根元素下的子元素
             List<Element> childElements = rootElement.elements();
             //5.遍歷子元素
             for (Element element : childElements) {
                    if( "servlet".equals(element.getName()))
                    {
                           Element elementName = element.element("servlet-name");
                           Element elementClass = element.element("servlet-class");
                           System.out.println(elementName.getText());
                           System.out.println(elementClass.getText());
                    }
             }
             } catch (DocumentException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
 
}
 
 
3、反射
 
爲了模擬服務器端程序,且能夠同時存在多個相似程序。故提供接口,接口中有3個方法,咱們人爲約定三個方法的調用順序:
public   interface  MyServlet
{
        public  void  init();
        
        public void service();
 
        public  void destory();
}
實現接口方法的類,而後Test類調用。
@Test
       public void testMyServlet()
       {
             MyServlet my = new MyServlet();
             my.init();
             my.service();
             my.destory();       
       }
 
測試程序咱們能夠直接new MyServlet();這種編碼方式咱們成爲硬編碼,即代碼寫死了。爲了後期程序的可擴展,開發中一般使用實現類的全限定類名。經過反射加載字符串指定的類,並經過反射建立實例。
 
什麼是反射?
JACA反射機制是在運行狀態中,對應任意一個類,都可以知道這個類的全部屬性和方法,對應任意一個對象,都可以調用它的任意一個方法和屬性。
反射
一、什麼是反射技術?
動態獲取指定類以及類中的內容(成員),並運行其內容。
應用程序已經運行,沒法在其中進行new對象的創建,就沒法使用對象。這時能夠根據配置文件的類全名(包名+類名)去找對應的字節碼文件,並加載進內存,並建立該類對象實例。這就須要使用反射技術完成
二、獲取class對象的三種方式
獲取Class對象的方式一:
經過對象具有的getClass方法(源於Object類的方法)。有點不方便,須要用到該類,並建立該類的對象,再調用getClass方法完成。
Person p = new Person();//建立Peron對象
Class clazz = p.getClass();//經過object繼承來的方法(getClass)獲取Person對應的字節碼文件對象
 
獲取Class對象的方式二:
       每個類型都具有一個class靜態屬性,經過該屬性便可獲取該類的字節碼文件對象。比第一種簡單了一些,僅用一個靜態屬性就搞定了。可是,仍是有一點不方便,還必需要使用到該類。
Class clazz = Person.class;
 
獲取Class對象方式三:
        * 去找找Class類中是否有提供獲取的方法呢?
        * 找到了,static Class forName(className);
        * 相對方便的多,不須要直接使用具體的類,只要知道該類的名字便可。
        * 而名字完成能夠做爲參數進行傳遞 ,這樣就能夠提升擴展性。
        * 因此爲了動態獲取一個類,第三種方式最爲經常使用。
    Class clazz = Class.forName("cn.itcast.bean.Person");//必須類全名
 
建立Person對象的方式
之前:1,先加載cn.itcast.bean.Person類進內存。
  2,將該類封裝成Class對象。
         3,根據Class對象,用new操做符建立cn.itcast.bean.Person對象。
      4,調用構造函數對該對象進行初始化。
cn.itcast.bean.Person p = new cn.itcast.bean.Person();
 
經過方式三:(此外還可使用構造,構造能夠指定參數---如String.class)
String className = "cn.itcast.bean.Person";
//1,根據名稱獲取其對應的字節碼文件對象
       1,經過forName()根據指定的類名稱去查找對應的字節碼文件,並加載進內存。
       2,並將該字節碼文件封裝成了Class對象。
       3,直接經過newIntstance方法,完成該對象的建立。
       4,newInstance方法調用就是該類中的空參數構造函數完成對象的初始化。
Class clazz = Class.forName(className);
//2,經過Class的方法完成該指定類的對象建立。
Object object = clazz.newInstance();//該方法用的是指定類中默認的空參數構造函數完成的初始化。
 
清單1,獲取字節碼文件中的字段。
Class clazz = Class.forName("cn.itcast.bean.Person");
//獲取該類中的指定字段。好比age
Field field = clazz.getDeclaredField("age");//clazz.getField("age");  //爲了對該字段進行操做,必需要先有指定類的對象。
Object obj = clazz.newInstance();
    //對私有訪問,必須取消對其的訪問控制檢查,使用AccessibleObject父類中的setAccessible的方法
field.setAccessible(true);//暴力訪問。建議你們儘可能不要訪問私有  
field.set(obj, 789);
    //獲取該字段的值。
Object o = field.get(obj);
System.out.println(o);
備註:getDeclaredField:獲取全部屬性,包括私有。
  getField:獲取公開屬性,包括從父類繼承過來的,不包括非公開方法。
清單2,獲取字節碼文件中的方法。
//根據名稱獲取其對應的字節碼文件對象
Class clazz = Class.forName("cn.itcast.bean.Person");
//調用字節碼文件對象的方法getMethod獲取class對象所表示的類的公共成員方法(指定方法),參數爲方法名和當前方法的參數,無需建立對象,它是靜態方法
Method method = clazz.getMethod("staticShow", null);
//調用class對象所表示的類的公共成員方法,須要指定對象和方法中的參數列表
method.invoke(null, null);
………………………………………………………………………………………………………
Class clazz = Class.forName("cn.itcast.bean.Person");  
    //獲取指定方法。
Method method = clazz.getMethod("publicShow", null);
    //獲取指定的類對象。
Object obj = clazz.newInstance();
method.invoke(obj, null);//對哪一個對象調用方法,是參數組
好處:大大的提升了程序的擴展性。 
 
@Test
       public void testMyServletClass()
       {
             try {
             String className = "com.scalpel.web.servlet.MyServlet";
             Class  clazz = Class.forName(className);
             MyServlet my = (MyServlet) clazz.newInstance();
             my.init();
             my.service();
             my.destory();
             } catch (Exception e) {                 
                    e.printStackTrace();
             }
       }
 
4、讀取配置文件,根據配置文件調用類的方法實現
一、添加dom4j-1.6.1.jar包   (使用dom4j解析配置文件)
二、添加xsd文檔    (web-app_2_5.xsd,改文檔爲Schema約束文檔)
三、編寫IMyServlet.java接口類 
四、實現接口類MyServlet.java
五、編寫web.xml文件
六、編寫測試類  TestMyServletAll.java   (根據解析web.xml文件來調用MyServlet類裏面的方法)
 
代碼:
IMyServlet.java
package com.scalpel.web.servletAll;
 
public interface IMyServlet {
       
       public void  init();
       
       public void service();
       
       public void destory();
 
}
 
MyServlet.java
package com.scalpel.web.servletAll;
 
public class MyServlet implements IMyServlet {
 
       @Override
       public void init() {
             System.out.println("MyServlet  star");
             
       }
 
       @Override
       public void service() {
             System.out.println("MyServlet  service");
             
       }
 
       @Override
       public void destory() {
             System.out.println("MyServlet  end");
             
       }
       
 
}
 
web.xml
<?xml version="1.0" encoding="UTF-8"?>
                    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>MyServlet</servlet-name>
              <servlet-class>com.scalpel.web.servletAll.MyServlet</servlet-class>
       </servlet>
       
       <servlet-mapping>
             <servlet-name>MyServlet</servlet-name>
             <url-pattern>/myServlet</url-pattern>
       </servlet-mapping>
       
       <servlet>
             <servlet-name>MyServletTwo</servlet-name>
              <servlet-class>com.scalpel.web.servletAll.MyServletTwo</servlet-class>
       </servlet>
       
       <servlet-mapping>
             <servlet-name>MyServletTwo</servlet-name>
             <url-pattern>/myServletTwo</url-pattern>
       </servlet-mapping>
                    
</web-app>
 
TestMyServletAll.java
package com.scalpel.web.servletAll;
 
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
 
public class TestMyServletAll {
       
       @Test
       public void testMyServlet()
       {
             try {
             //1.建立解析器對象
             SAXReader saxReader = new SAXReader();
             //2.使用解析器加載web.xml文檔獲得document對象
             Document document = saxReader.read("src/com/scalpel/web/servletAll/web.xml");
             //3.獲取根元素節點
             Element rootElement = document.getRootElement();
             //4.根據元素名稱獲取子元素節點(獲取第一個servlet)
             Element servletElement = rootElement.element("servlet");
             //5.根據元素名稱獲取servlet-class的文本節點
             String servletClass = servletElement.element("servlet-class").getText();
             //System.out.println(servletClass);
             //6.經過類全名獲取字節碼文件
             Class clazz = Class.forName(servletClass);           
             //7.建立實例對象
             MyServlet  my = (MyServlet) clazz.newInstance();
             //8.調用實例對象裏面的方法
             my.init();
             my.service();
             my.destory();
             
             } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
}
 
備註:很簡單的代碼。可是思想很重要,在公司中,每一個人負責的模塊不同,不必定可以看到別人負責的源代碼,當你須要調用其餘同事寫的接口的時候,就須要查看web.xml(配置文件)文檔,而後解析,調用其餘同事的接口。最後完成本身負責模塊的功能。
相關文章
相關標籤/搜索