Spring 自定义标签

Spring 工作流程是先加载解析xml配置文件:配置文件中存在默认的标签,也可以自定义标签。解析默认标签调用:

 1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
 2         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
 3             importBeanDefinitionResource(ele);
 4         }
 5         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
 6             processAliasRegistration(ele);
 7         }
 8         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
 9             processBeanDefinition(ele, delegate);
10         }
11         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
12             // recurse
13             doRegisterBeanDefinitions(ele);
14         }
15     }

解析自定义标签调用:

1 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
2         String namespaceUri = getNamespaceURI(ele);
3         NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
4         if (handler == null) {
5             error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
6             return null;
7         }
8         return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
9     }

parseCustomElement

下面我们正式开始搞Spring自定义标签:


1.搞一个Bean: 这是一个很普通的pojo, 只是用来接收配置文件。

 1 /**
 2  * @filename: User.java
 3  * @author: Wang Chinda
 4  * @date: 2018-05-21
 5  * @version: v1.0
 6  * @modify_history: -
 7  * 20180521   Wang Chinda   create
 8  * 20180521   Wang Chinda   modify   method()
 9  */
10 package com.itdoc.learn.source.custom;
11
12 /**
13  * @desc 自定义标签测试类
14  * @author Wang Chinda
15  * @create 2018-05-21 14:03
16  */
17 public class User {
18     private String id;
19     private String userName;
20     private String email;
21
22     public String getId() {
23         return id;
24     }
25
26     public void setId(String id) {
27         this.id = id;
28     }
29
30     public String getUserName() {
31         return userName;
32     }
33
34     public void setUserName(String userName) {
35         this.userName = userName;
36     }
37
38     public String getEmail() {
39         return email;
40     }
41
42     public void setEmail(String email) {
43         this.email = email;
44     }
45 }

User

2.定义一个文件描述组件[xml schama difinition (xsd)]: 在classpath下创建一个META-INF文件夹, 在此文件夹下创建一个spring-user.xsd文件。

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

spring-user

targetNamespace="http://www.itdoc.com/schema/user" 和xmlns="http://www.itdoc.com/schema/user"都是自定义的。

文件中的片段意义:

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

显示 schema 中用到的元素和数据类型来自命名空间 "http://www.w3.org/2001/XMLSchema"。同时它还规定了来自命名空间 "http://www.w3.org/2001/XMLSchema" 的元素和数据类型应该使用前缀 xsd

xmlns="http://www.itdoc.com/schema/user"

指出默认的命名空间是 "http://www.itdoc.com/schema/user"

targetNamespace="http://www.itdoc.com/schema/user"

显示被此 schema 定义的元素 (note, to, from, heading, body) 来自命名空间: "http://www.itdoc.com/schema/user"

elementFormDefault="qualified"

指出任何 XML 实例文档所使用的且在此 schema 中声明过的元素必须被命名空间限定

在上面的xsd文件描述中添加一个targetNamespace, 并在这个命名空间中定义了一个name为user的element, user有3个属性id、userName、email, 三个属性均为string类型。

3.创建一个用来解析xsd文件的定义和组件定义的文件并实现BeanDefinitionParser接口。此例中我们继承AbstractSingleBeanDefinitionParser抽象类.

 1 /**
 2  * @filename: UserBeanDefinitionParse.java
 3  * @author: Wang Chinda
 4  * @date: 2018-05-21
 5  * @version: v1.0
 7  * @modify_history: -
 8  * 20180521   Wang Chinda   create
 9  * 20180521   Wang Chinda   modify   method()
10  */
11 package com.itdoc.learn.source.custom;
12
13 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
14 import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
15 import org.springframework.util.StringUtils;
16 import org.w3c.dom.Element;
17
18 /**
19  * @desc 自定义bean定义解析
20  * @author Wang Chinda
21  * @create 2018-05-21 14:20
22  */
23 public class UserBeanDefinitionParse extends AbstractSingleBeanDefinitionParser {
24
25     /**
26      * Element对应的类
27      * @param element
28      * @return
29      */
30     @Override
31     protected Class<?> getBeanClass(Element element) {
32         return User.class;
33     }
34
35     @Override
36     protected void doParse(Element element, BeanDefinitionBuilder builder) {
37         String userName = element.getAttribute("userName");
38         String email = element.getAttribute("email");
39
40         // 将提取到的数据放入到BeanDefinitionBuilder中, 待完成所有bean的解析后统一注册到beanFactory中
41         if (StringUtils.hasText(userName)) {
42             builder.addPropertyValue("userName", userName);
43         }
44
45         if (StringUtils.hasText(email)) {
46             builder.addPropertyValue("email", email);
47         }
48     }
49 }

UserBeanDefinitionParse

4.创建一个Handler文件, 扩展自NamespaceHandlerSupport, 目的是将组件注册到Spring容器中

/**
 * @filename: MyNameSpaceHandler.java
 * @author: Wang Chinda
 * @date: 2018-05-21
 * @version: v1.0
 * @modify_history: -
 * 20180521   Wang Chinda   create
 * 20180521   Wang Chinda   modify   method()
 */
package com.itdoc.learn.source.custom;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 * @desc 自定义命名空间控制器
 * @author Wang Chinda
 * @create 2018-05-21 14:28
 */
public class MyNameSpaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParse());
    }
}

MyNameSpaceHandler

以上代码功能是当遇到<xxx:user 这样开头的元素, 就会交给UserBeanDefinitionParse去解析。

5.编写spring.handlers和spring.schemas文件, 默认位置是在classpath:/META-INF/文件夹下

注意:

1) 这两个文件名不允许改,若想更改的话,得需要连带更改spring源码文件。

2) 为什么将spring.handlers和spring.schemas放在META-INF文件夹下, 因为Spring默认到这个文件夹中寻找spring.handlers和spring.schemas文件。

spring.handlers:

http\://www.itdoc.com/schema/user=com.itdoc.learn.source.custom.MyNameSpaceHandler

spring.schemas:

http\://www.itdoc.com/schema/user.xsd=META-INF/spring-user.xsd

注意:

1) 冒号用来转译的。

2) 命名空间一定不要写错, 要和targetNamespace中定义的相同。

Spring加载自定义标签的大致流程是遇到自定义标签就会去spring.handler和spring.schemas中去找对应的handler和xsd,进而找到对应的MyNameSpaceHandler以及解析元素的UserBeanDefinitionParse, 从而完成了整个自定义标签的解析。

6.创建测试配置文件, 在文件中引入对应的命名空间及xsd, 便可以使用自定义标签。

 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:myTag="http://www.itdoc.com/schema/user"
 5        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 6        http://www.itdoc.com/schema/user http://www.itdoc.com/schema/user.xsd">
 7
 8     <myTag:user id="customBeanTest" userName="name" email="[email protected]"/>
 9
10 </beans>

7.测试

 1 /**
 2  * @filename: CustomMain.java
 3  * @author: Wang Chinda
 4  * @date: 2018-05-21
 5  * @version: v1.0
 6  * @modify_history: -
 7  * 20180521   Wang Chinda   create
 8  * 20180521   Wang Chinda   modify   method()
 9  */
10 package com.itdoc.learn.source.custom;
11
12 import org.springframework.context.ApplicationContext;
13 import org.springframework.context.support.ClassPathXmlApplicationContext;
14
15 /**
16  * @desc 测试
17  * @author Wang Chinda
18  * @create 2018-05-21 14:58
19  */
20 public class CustomMain {
21
22     public static void main(String[] args) {
23         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/customTest.xml");
24         User user = (User) applicationContext.getBean("customBeanTest");
25         System.out.println(user.getEmail() + " ---- " + user.getUserName());
26     }
27 }

控制台显示:

原文地址:https://www.cnblogs.com/goodcheap/p/9068373.html

时间: 2024-08-01 09:25:25

Spring 自定义标签的相关文章

Spring 自定义标签配置

前景:经常使用一些依赖于Spring的组件时,发现可以通过自定义配置Spring的标签来实现插件的注入,例如数据库源的配置,Mybatis的配置等.那么这些Spring标签是如何自定义配置的?学习Spring标签的自定义配置为以后实现分布式服务框架做技术储备. 技术分析:Spring的标签配置是通过XML来实现的,通过XSD(xml Schema Definition)来定义元素,属性,数据类型等. Spring自定义标签解析 1.Spring启动时通过扫描根目录下的META-INF文件下的sp

spring 自定义标签 学习

自定义配置文件到spring 中,有时候想做一些数据结构的配置化信息,根据业务做一个扩展. 首先: 在项目的META-INF目录下新建两个文件spring.handlers,和spring.shcemas Spring.handlers在类org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver中已经写死了要取mapping的handlerMappingsLocation的路径 public static fina

spring 自定义标签 学习二

在上篇中写的只支持写属性,不支持标签property的写法,但是如果有时候我们还想做成支持 property的用法,则可以在xsd中增加spring 自带的xsd引用 修改xsd文件如下: <?xml version="1.0"encoding="UTF-8"?> <xsd:schema xmlns="http://www.ruishenh.com/custom/myTest" xmlns:xsd="http://ww

(转载)Spring自定义标签的原理

Spring自定义标签的原理 XML通常通过DTD.XSD定义,但DTD的表达能力较弱,XSD定义则能力比较强,能够定义类型,出现次数等.自定义标签需要XSD支持,在实现时使用Namespace扩展来支持自定义标签. <bean id="beanId" class="com.xxx.xxxx.Xxxxx"> <property name="property1"> <value>XXXX</value>

Spring自定义标签

一.原理: 1.Spring通过XML解析程序将其解析为DOM树, 2.通过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDefinition. 3.再通过Spring自身的功能对BeanDefinition实例化对象. 二.自定义标签步骤 1.定义三个文件 META-INF/spring.handlers http\://www.newlandframework.com/dubbo=com.newlandframewor

dubbo源码学习(二) : spring 自定义标签

做dubbo的配置时很容易发现,dubbo有一套自己的标签,提供给开发者配置,其实每一个标签对应着一个 实体,在容器启动的时候,dubbo会对所有的配置进行解析然后将解析后的内容设置到实体里,最终dubbo会根据实体中的值生成贯穿全局的统一URL.利用自定义标签使配置简单明了化,与spring完美融合.下面自己写一个自定义标签,主要需要如下 几个步骤: 1.编写实体类2.编写Parser解析类3.编写NameSpaceHandle类4.配置spring.handlers5.配置spring.sc

自己构建一个Spring自定义标签以及原理讲解

平时不论是在Spring配置文件中引入其他中间件(比如dubbo),还是使用切面时,都会用到自定义标签.那么配置文件中的自定义标签是如何发挥作用的,或者说程序是如何通过你添加的自定义标签实现相应的功能的呢?且看下文. 通过对本文的阅读,你会在阅读涉及到自定义标签的源码功能时事半功倍,而且还可以自己动手做出一个自己的自定义标签. 先呈上我自己在本地实现自定义标签的代码及对应讲解: 1.先无脑输出一个测试要用到的Bean类 1 public class User { 2 3 private Stri

Spring的自定义标签

当Spring拿到一个元素时首先要做的是根据命名空间进行解析,如果是默认的命名空间,则使用parseDefaultElement方法进行元素解析,否则使用parseCustom Element方法进行解析. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl =

dubbo源码—dubbo自定义spring xml标签

dubbo为了和spring更好的集成,提供了一些xml配置标签,也就是自定义标签 spring自定义标签 spring自定义标签的方式如下: 设计配置属性和JavaBean 编写xsd文件,校验xml属性和便于编辑器提示 编写NamespaceHandler和BeanDefinitionParser解析xml对应的标签 编写spring.handlers和spring.schemas串联起所有部件,放在META_INF下面 在xml中引入对应的标签就可以使用 dubbo自定义标签 dubbo对