1. 程式人生 > >Spring——使用自定義標簽

Spring——使用自定義標簽

組件註冊 body match lex swa 關於 文件 fin 全面

文章內容參考了《Spring源碼深度解析》一書。自己照著書中內容做了一遍,不懂的地方以及采坑的地方會在文中記錄。

推薦一篇post,關於Spring配置文件的命名空間:

https://www.cnblogs.com/gonjan-blog/p/6637106.html

我們暫時只是知道使用Spring的常規標簽,加個bean,事務,Aop等等。隨著滿足業務的需求,同時降低程序員的工作量,我們有時需要自己定制一些標簽。話補多少,下面進入主題。

自定義標簽的使用

擴展Spring自定義標簽大致需要如下幾步:(把大象裝冰箱,需要三步,開門,放,關門。。。)

1.創建需要擴展的組件

2.定義XSD文件描述組件內容

3.創建一個文件,實現BeanDefinitionParser接口,用來解析XSD文件中的定義和組件定義

4.創建Handler文件,擴展字NamespaceHandlerSupport,目的是將組件註冊到Spring容器

5.編寫Spring.handlers和Spring.schemas文件

上述,五點看完了,我最開始時一頭霧水,這是什麽啊?別著急,跟哥往下走。下面有好東西,保證不打暈你。

例子:

1.創建POJO,接收配置文件

 1 package test.customtag;
 2 
 3 public class User {
 4     private String userName;
5 public String getUserName() { 6 return userName; 7 } 8 public void setUserName(String userName) { 9 this.userName = userName; 10 } 11 private String email; 12 public String getEmail() { 13 return email; 14 } 15 public void setEmail(String email) {
16 this.email = email; 17 } 18 }

2.定義一個XSD文件描述組件內容

src/main/resources/META-INF/user.xsd

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/schema/user" xmlns:tns="http://www.example.org/schema/user" elementFormDefault="qualified">
 3     <element name="user2">
 4         <complexType>
 5             <attribute name ="id" type = "string"/>
 6             <attribute name ="userName" type = "string"/>
 7             <attribute name ="email" type = "string"/>
 8         </complexType>
 9     </element>
10 </schema>

描述了一個targetNamespace,並且創建了一個element user2。裏面有三個attribute。主要是為了驗證Spring配置文件中的自定義格式。再進一步解釋,就是,Spring位置文件中使用的user2自定義標簽中,屬性只能是上面的三種,有其他的屬性的話,就會報錯。

網上有人說element complexType等等這些標簽要用XSD開頭的標簽,但是我這裏沒有用也能成功的執行,我猜測可能是spring的版本問題。(我這個猜測沒有依據)

大家對這個XSD可能會有疑問,不要擔心。推薦一篇post,裏面講解的很好,地址放在文章開頭那裏。

3.創建文件,實現BeanDefinitionParser接口,用來解析XSD文件中的定義和組件定義

 1 package test.customtag;
 2 
 3 
 4 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 5 import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
 6 import org.springframework.util.StringUtils;
 7 import org.w3c.dom.Element;
 8 
 9 public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
10 
11     @SuppressWarnings("rawtypes")
12     protected Class getBeanClass(Element element) {
13         return User.class;
14     }
15     
16     protected void doParse(Element element, BeanDefinitionBuilder bean) {
17         String userName = element.getAttribute("userName");
18         String email = element.getAttribute("email");
19         if (StringUtils.hasText(userName)) {
20             bean.addPropertyValue("userName", userName);
21         }
22         if (StringUtils.hasText(email)){
23             bean.addPropertyValue("email", email);
24         } 
25         
26     }
27 }

上文,雖說是繼承了AbstractSingleBeanDefinitionParser ,但根本上來說,是實現了BeanDefinitionParser接口。

4.創建Handler文件,擴展自NamespaceHandlerSupport,目的是將組件註冊到Spring容器中。

 1 package test.customtag;
 2 
 3 import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
 4 
 5 public class MyNamespaceHandler extends NamespaceHandlerSupport {
 6 
 7     public void init() {
 8 
 9         registerBeanDefinitionParser("user2", new UserBeanDefinitionParser());
10     }
11 
12 }

5.編寫Spring.handlers和Spring.schemas文件

路徑:src/main/resources/META-INF/Spring.handlers

1 http\://www.example.org/schema/user=test.customtag.MyNamespaceHandler

路徑:src/main/resources/META-INF/Spring.schemas

1 http\://www.example.org/schema/user.xsd=META-INF/user.xsd

\ 是轉義字符的概念。

6.創建測試配置文件

路徑:src/main/resources/test.xml

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4     xmlns:myname2="http://www.example.org/schema/user"
5     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
6     http://www.example.org/schema/user http://www.example.org/schema/user.xsd">
7     
8     <myname2:user2 id = "testbean" userName = "lee" email = "bbb"/>
9 </beans>

在第4行這裏引入了myname2對應的命名空間,它會到第六行(http://www.example.org/schema/user.xsd)找到對應XSD文件進行check。第六行的user.xsd文件的位置,到步驟5裏的Spring.schemas裏去參照。

在這裏說明一下自己遇到的疑問:第八行,自己eclipse報了紅叉,信息如下:

Multiple annotations found at this line:
- cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element ‘myname2:user2‘.
- schema_reference.4: Failed to read schema document ‘http://www.example.org/schema/user.xsd‘, because 1) could not find the
document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.

但是,我沒有解決它,直接執行第6步的代碼,最後成功執行了,搞不懂原因。

6.測試。

 1 package test.customtag;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 public class Tst {    
 7     public static void main(String[] args) {    
 8         ApplicationContext beans=new ClassPathXmlApplicationContext("classpath:test.xml");    
 9         User user=(User)beans.getBean("testbean");    
10         System.out.println("username:"+user.getUserName()+"  "+"email:"+user.getEmail());    
11     }    
12 }   

文章記錄的不是特別的詳細,有一些知識點沒有全面的記錄。但是,跟著一步步做,Spring自定義標簽的實現,應該是沒有問題了。稍後,有時間,會記錄Sping源碼中,關於自定義標簽解析的部分。與君共勉。

Spring——使用自定義標簽