【spring源码学习】spring的IOC容器之自定义xml配置标签扩展namspaceHandler向IOC容器中注册bean
【spring以及第三方jar的案例】在spring中的aop相关配置的标签,线程池相关配置的标签,都是基于该种方式实现的。包括dubbo的配置标签都是基于该方式实现的。
【一】原理
===>spring在解析xml标签,一旦不是以<bean>开头的元素,就会走org.springframework.beans.factory.xml.BeanDefinitionParserDelegate的parseCustomElement(Element ele)方法解析自定义的标签
===>在该方法里会根据xml中的命名空间去查询该标签对应的NamespaceHandler接口的实现类去解析该配置标签。该接口解析该配置标签,并形成BeanDefinition注册到IOC容器中。
===>该扩展需要做的内容:
(1)建立spring.handlers文件,这是在解析xml配置文件的时候,spring会通过xml文件头的命名空间,去找该配置文件中的NamespaceHandler的实现类。
(2)建立spring.schemas文件,这是在xml文件中配置自定义标签的标签合法验证,也是合法检验。如果随意填写配置标签,spring将无法解析。
(3)在所扩展的项目的resources目录下,建立META-INF目录,并将两个文件放置在目录下。
(4)将spring.schemas中的xsd文件配置在随意的类路径下。关于xsd文件,可以了解:http://www.w3school.com.cn/schema/index.asp
(5)建立NamespaceHandler接口的实现类,建立BeanDefinitionParser的实现类。用于解析自已定义标签的内容。
【二】实现例子:定义一个自定义标签,实现一个类ZKClient的bean通过NamespaceHandler注册IOC容器。本例子已经通过测试。不写测试方法,只写实现过程。
(1)spring.handlers文件内容
http\://localhost.com/sxf=com.mobile.thinks.manages.namespaceHandler.SxfNameSpaceHandler
(2)spring.schemas文件内容
http\://localhost.com/sxf.xsd=com/mobile/thinks/manages/namespaceHandler/sxf.xsd
(3)xsd文件内容
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://localhost.com/sxf"
xmlns="http://www.w3school.com.cn"
elementFormDefault="qualified"> <xsd:element name="zk">
<xsd:complexType>
<xsd:attribute name="host" use="required" >
<xsd:simpleType>
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="port" use="required" >
<xsd:simpleType>
<xsd:restriction base="xsd:integer"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="user" use="required" >
<xsd:simpleType>
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="pwd" use="required" >
<xsd:simpleType>
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
(4)spring的xml配置文件内容
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:sxf="http://localhost.com/sxf"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://localhost.com/sxf
http://localhost.com/sxf.xsd "> <sxf:zk host="127.0.0.1" port="2181" user="shangxiaofei" pwd="smxcyx"/> <!-- <context:property-placeholder location="classpath:resources.properties"/> --> <!-- 扫描注解Bean -->
<context:component-scan base-package="com.mobile.thinks.**">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<context:include-filter type="annotation" expression="org.springframework.beans.factory.annotation.Autowired"/>
</context:component-scan> </beans>
(5)NamespaceHandler接口实现类的内容
package com.mobile.thinks.manages.namespaceHandler; import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* 自定义标签的注解解释器
* @author sxf
*
*/
public class SxfNameSpaceHandler extends NamespaceHandlerSupport { /**
* 初始化zk元素的具体解析器
*/
@Override
public void init() {
registerBeanDefinitionParser("zk", new ZkBeanDefinitionParser());
} }
(6)BeanDefinitionParser接口实现类的内容
package com.mobile.thinks.manages.namespaceHandler; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element; public class ZkBeanDefinitionParser implements BeanDefinitionParser{ private static final String HOST ="host";
private static final String PORT="port";
private static final String USER="user";
private static final String PWD="pwd"; /**
* 解析标签,形成特定的beanDefinition加入到ioc容器中
*/
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ZkClient.class);
String host=element.getAttribute("host");
String port=element.getAttribute("port");
String user=element.getAttribute("user");
String pwd=element.getAttribute("pwd");
builder.addPropertyValue("host",host);
builder.addPropertyValue("port", Integer.valueOf(port));
builder.addPropertyValue("user", user);
builder.addPropertyValue("pwd", pwd);
parserContext.getRegistry().registerBeanDefinition("zkClient", builder.getBeanDefinition());
return builder.getBeanDefinition();
} }
(7)Zkclient类的内容,将来在项目中用一下方式直接使用该类
@Autowired
private ZkClient zkClient;
package com.mobile.thinks.manages.namespaceHandler;
/**
* 该类用自定义的NameSpaceHandler类解析配置文件向IOC容器中注册
* @author sxf
*
*/
public class ZkClient { private String host;
private int port;
private String user;
private String pwd; public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
} }
【三】项目结构图

【&&】需要注意的点,当maven打包的时候,默认不会将sxf.xsd文件打包进jar包,将来项目用到的时候就不会从本地读取到该sxf.xsd文件,则需要在pom.xml文件配置如下,才可以将文件打包到相应的位置。也可以将其他格式的文件,打包到jar包相应的位置,只需要修改相应文件的后缀。
<build>
<!-- 打成jar包的名字 -->
<finalName>test</finalName>
<!-- 这样也可以把所有的readme文件,打包到相应位置。其他的比如XX.xml文件,也是同样配置 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.txt</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xsd</include>
</includes>
</resource>
</resources>
</build>
该项目的jar完整的pom.xml文件
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.</modelVersion>
<parent>
<groupId>com.mobile</groupId>
<artifactId>thinks</artifactId>
<version>0.0.-SNAPSHOT</version>
</parent>
<groupId>com.mobile</groupId>
<artifactId>thinks-manages</artifactId>
<version>1.0.</version>
<name>thinks-manages</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-</project.build.sourceEncoding>
</properties>
<build>
<!-- <finalName>test</finalName> 打包成默认名字 -->
<!-- 这样也可以把所有的readme文件,打包到相应位置。其他的比如XX.xml文件,也是同样配置 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.txt</include>
<include>**/*.xml</include>
<include>**/*.handlers</include>
<include>**/*.schemas</include>
<include>**/*.drl</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xsd</include>
</includes>
</resource>
</resources>
</build>
<dependencies>
<dependency>
<groupId>com.mobile</groupId>
<artifactId>thinks-service</artifactId>
<version>${thinks.service.version}</version>
</dependency>
<dependency>
<groupId>com.mobile</groupId>
<artifactId>thinks-core</artifactId>
<version>${thinks.core.version}</version>
</dependency>
<dependency>
<groupId>com.mobile</groupId>
<artifactId>thinks-commons</artifactId>
<version>${thinks.commons.version}</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.</version>
<scope>test</scope>
</dependency> <!-- drools规则引擎 -->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>knowledge-api</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-jsr94</artifactId>
<version>${drools.version}</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<!-- drools升级6.5.0.final版本依赖 -->
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
</dependency>
</dependencies>
</project>
================xsd文件定义语法================
- xsd:element 表示定义标签
- xsd:extension 如java中的继承,把现有的定义继承进来
- xsd:attribute 标签带有的属性
- xsd:restriction 对标签改属性进一步的限制,进行一些值的约束
【spring源码学习】spring的IOC容器之自定义xml配置标签扩展namspaceHandler向IOC容器中注册bean的更多相关文章
- spring源码学习——spring整体架构和设计理念
Spring是在Rod Johnson的<Expert One-On-One J2EE Development and Design >的基础上衍生而来的.主要目的是通过使用基本的java ...
- Spring源码学习
Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...
- spring源码学习之路---IOC初探(二)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...
- Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件
写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...
- Spring 源码学习 04:初始化容器与 DefaultListableBeanFactory
前言 在前一篇文章:创建 IoC 容器的几种方式中,介绍了四种方式,这里以 AnnotationConfigApplicationContext 为例,跟进代码,看看 IoC 的启动流程. 入口 从 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md
写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...
- Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签
写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...
- Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作
写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...
随机推荐
- 物理机内存模型与java内存模型
多线程缓存一致性问题 程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数 ...
- Record and accumulation
最近有同学在准备校招的问题,问我几个问题,我觉得有必要把大家的问题汇总下: 1.在设计变量的while指挥时候,可以利用弹栈的特性以及Java传值 只是传递的副本 去控制 : https://www ...
- NOIP2018没有什么新闻
noip结束了.站在六中门口,回头望了一眼偌大的校园,萧瑟的秋风卷起残败的落叶,纷纷扬扬地洒落,洒落在OIer的心头. 今年的noip没有什么新闻,有的只是又一次被喷的题,和又一次挂掉的我. Day ...
- 转: 在hibernate中查询使用list,map定制返回类型
在使用hibernate进行查询时,使用得最多的还是通过构建hql进行查询了.在查询的过程当中,除使用经常的查询对象方法之外,还会遇到查询一个属性,或一组聚集结果的情况.在这种情况下,我们通常就需要对 ...
- MVC bootstrap 实现 bootstrap table 左右传递数据
源码: @{ ViewBag.Title = "Index"; } @using BC.Platform.UPMS.Models; <!DOCTYPE html> &l ...
- Ubuntu 通过APT安装Tomcat
Ubuntu 通过APT安装Tomcat 安装 sudo apt-get install tomcat8 tomcat8-docs tomcat8-examples tomcat8-admin # s ...
- django中Model表的反向查询
很多时候需要在多张表之间进行跨表查询,这其中外键是必须存在的,而通过外键所处的表的对象进行跨表查询, 称为正向查询.反之,则是反向查询. 正向查询很简单,这里不谈. 主要谈下反向查询. class U ...
- 新东方雅思词汇---8.1、reckon
新东方雅思词汇---8.1.reckon 一.总结 一句话总结:reck(注意,留心)+on 英 ['rek(ə)n] 美 ['rɛkən] vt. 测算,估计:认为:计算 vi. 估计:计算:猜 ...
- freemarker报 java.io.FileNotFoundException:及TemplateLoader使用
使用过freemarker的肯定其见过如下情况: java.io.FileNotFoundException: Template xxx.ftl not found. 模板找不到.可能你会认为我明明指 ...
- C语言之内存四区模型和函数调用模型
内存四区模型 流程说明1.操作系统把物理硬盘代码load到内存2.操作系统把c代码分成四个区3.操作系统找到main函数入口执行 1.内存四区: 一个由c/C++编译的程序占用的内存分为以下几个部 ...