别人要是能破解你的网络监控安装步骤图解是不是也能监控你上网的电脑手机微信qq

spring自定义标签实现 - 淘宝百岁 - ITeye技术网站
博客分类:
spring中编写配置可以用两种方式:
普通的通过 &bean id="" class=""&&property name="" ref=""&&/bean& 这种默认标签配置方式
自定义Bean 配置方式,例如:
&?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:tsearcher="/terminator/tsearcher"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
/terminator/tsearcher /terminator/tsearcher.xsd"&
&tsearcher:parent id="testparent"&
&tsearcher:child /&
&/tsearcher:parent&
这种自定义的配置方式,在spring的实现中已经有部门实现,分别在几个命令空间中详细说明请查看(http://static.springsource.org/spring/docs/2.0.x/reference/xsd-config.html)
下面通过一个例子来说明一下,如何实现spring 自定义bean的方式来配置对象:
首先,定义两个properties文件,
一个是 spring.handlers 这个文件的作用是将配置文件中的命名空间与处理命名空间的handler(NamespaceHandlerSupport)联系起来,
另外一个文件是spring.schemas 文件,这个文件的作用是定义xsd文件的虚拟路径
spring.handlers例子:
http\:///terminator/tsearcher=com.taobao.terminator.tag.TermiantorTSearcherNamespaceHandler
spring.shcemas例子:
http\:///terminator/tsearcher.xsd=com/taobao/terminator/xsd/tsearcher.xsd
接下来要写一个namespaceHandler 类,用来为这个名称空间下的每个标签定义解析器。
例如,上面提到的TermiantorTSearcherNamespaceHandler:
import org.springframework.beans.factory.xml.NamespaceHandlerS
public class TermiantorTSearcherNamespaceHandler extends
NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("parent", new ParentBeanParser());
registerBeanDefinitionParser("child", new ChildParser());
init方法中调用了两次registerBeanDefinitionParser,申明了parent,child 标签的解析器。
parent标签和child标签的关系是父子关系,spring配置文件如下:
&?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:tsearcher="/terminator/tsearcher"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
/terminator/tsearcher /terminator/tsearcher.xsd"&
&tsearcher:parent id="testparent"&
&tsearcher:child /&
&/tsearcher:parent&
定义tsearcher.xsd的xml元素结构信息:
&?xml version="1.0" encoding="UTF-8"?&
&xsd:schema xmlns="/terminator/tsearcher"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="/terminator/tsearcher"
elementFormDefault="qualified" attributeFormDefault="unqualified"&
&xsd:import namespace="http://www.springframework.org/schema/beans" /&
&xsd:element name="parent"&
&xsd:complexType&
&xsd:complexContent&
&xsd:extension base="beans:identifiedType"&
&xsd:sequence&
&xsd:element ref="child" /&
&/xsd:sequence&
&/xsd:extension&
&/xsd:complexContent&
&/xsd:complexType&
&/xsd:element&
&xsd:element name="child"&
&xsd:complexType&
&xsd:complexContent&
&xsd:extension
base="beans:identifiedType"&
&/xsd:extension&
&/xsd:complexContent&
&/xsd:complexType&
&/xsd:element&
&/xsd:schema&
这里最重要的是parent标签的解析器ParentBeanParser,在doParse方法中,还需要启动子标签child的解析流程,不然的话子标签child不会被解析:
import org.springframework.beans.factory.support.BeanDefinitionB
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionP
import org.springframework.beans.factory.xml.ParserC
import org.springframework.util.xml.DomU
import org.w3c.dom.E
* @author 百岁()
public class ParentBeanParser extends AbstractSimpleBeanDefinitionParser {
protected void doParse(Element element, ParserContext parserContext,
BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
builder.addPropertyValue("child", parserContext.getDelegate()
.parseCustomElement(
DomUtils.getChildElementByTagName(element, "child"),
builder.getRawBeanDefinition()));
protected Class&Parent& getBeanClass(Element element) {
return Parent.
这里特别要说明的是,在调用parserContext.getDelegate()
.parseCustomElement(DomUtils.getChildElementByTagName(element, "child"), builder.getRawBeanDefinition())
方法的时候,方法parseCustomElement的第二个beanDefinition参数是必须的,不然的话框架会认为这个元素是根结点元素,必须要有一个id属性。
接下来又出现一个新的需求,如果parent和child是一对多关系,例如标签格式如下:
&tsearcher:parent id="testparent"&
&tsearcher:child name="1"/&
&tsearcher:child name="2"/&
&tsearcher:child name="3"/&
&/tsearcher:parent&
显然,用上面介绍的ParentBeanParser这个类中的解析标签的方式是不能满足需求的。
如果要知道如何解决一对多的关系请查阅下一篇博客()
mozhenghua
浏览: 131203 次
来自: 杭州
她的酒窝 写道你好,楼主,将数据库中的几张业务表打成宽表的方式 ...
大牛的思想才是最好的东西
你的 demo 似乎写错了,我理解了你的意思 ,spring
你好,楼主,将数据库中的几张业务表打成宽表的方式,这个打宽表的 ...
Phoenix0101 写道好像知道你是如何获取的maven的 ...【Spring】IOC核心源码学习(三):bean标签和自定义标签实现原理 - singleAnt - ITeye技术网站
博客分类:
本文将解析spring bean定义标签和自定义标签的解析实现原理。
这里说的标签仅限于以xml作为bean定义描述符的spring容器,继承AbstractXmlApplicationContext的一些子
容器,如XmlApplicationContext、ClassPathXmlApplicationContext、
FileSystemXmlApplicationContext等。同时也仅限于描述schema作为标签定义的情况。
容器常用标签和自定义标签
资源定义的容器配置是我们最常见的一种方式。
容器需要解析
的标签,并把
的定义转化为内部的结构
BeanDifinition
的标签有很多种,其支持的常见的标签有:
最常用的,定义一个普通
&bean id="myBean"
class="com.test.MyBean" lazy-init="true"/&
等,提供事务配置通用支持。
&tx:advice id="txAdvice" transaction-manager="transactionManager"&
&tx:attributes&
&tx:method name="save*"/&
&tx:method name="remove*"/&
&tx:method name="*" read-only="true"/&
&/tx:attributes&
&/tx:advice&
&aop:config&,&aop:
aspectj-autoproxy&
等提供代理
通用配置支持。
&aop:config proxy-target-class="true"&
&aop:advisor pointcut="..." advice-ref="txAdvice"/&
&aop:advisor pointcut="..." advice-ref="fooAdvice"/&
&/aop:config&
提供在容器内配置一些JDK自带的工具类、集合类和常量的支持。
&util:list id="list" list-class="java.util.ArrayList"&
&value&listValue1&/value&
&value&listValue2&/value&
&/util:list&
&util:map id="map"&
&entry key="key1"
value="mapValue1"&&/entry&
&entry key="key12" value="mapValue2"&&/entry&
&/util:map&
属性的简单访问
&bean id="loginAction" class="com.test.LoginAction" p:name="test"&&/bean&
&lang:groovy&&lang:jruby&等,提供对动态脚本的支持。
&lang:groovy id="test"
refresh-check-delay="5000"
script-source="classpath:com/test/groovy/test.groovy"&
&/lang:groovy&
&jee:jndi-lookup/&等,对一些javaEE规范的bean配置的简化,如jndi等。
&jee:jndi-lookup id="simple"
jndi-name="jdbc/MyDataSource"
cache="true"
resource-ref="true"
lookup-on-startup="false"
expected-type="com.myapp.DefaultFoo"
proxy-interface="com.myapp.Foo"/&
基本上每一种标签都是用来定义一类
的(P标签除外)。以上都是
自带的一些标签,当然
也支持自定义标签。其实
这些也可以认为是自定义标签,不过是由
扩展的而已。
其实所有的bean定义都可以用bean标签来实现定义的。而衍生这种自定义标签来定义
有几个好处:
见名知意。
对于同一类的通用
。封装不必要的配置,只给外部暴露一个简单易用的标签和一些需要配置的属性。很多时候对于一个框架通用的
,我们不需要把
的所有配置都暴露出来,甚至像类名、默认值等我们都想直接封装,这个时候就可以使用自定义标签了,如:
&services:property-placeholder /&
可能这个标签就默认代表配置了一个支持
property placeholder
,我们都不需要去知道配这样一个
的类路径是什么。
可以说自定义标签是
容器的一个扩展点,本身
自己的很多标签也是基于这个设计上面来构造出来的。
Spring 对于自定义(声明式)bean标签解析如何设计
的定义方式有千千万万种,无论是何种标签,无论是何种资源定义,无论是何种容器,最终的
定义内部表示都将转换为内部的唯一结构:
BeanDefinition
。外部的各种定义说白了就是为了方便配置。
提供对其支持的标签解析的天然支持。所以只要按照
的规范编写
配置文件。所有的配置,在启动时都会正常的被解析成
BeanDefinition
。但是如果我们要实现一个自定义标签,则需要提供对自定义标签的全套支持。
我们知道要去完成一个自定义标签,需要完成的事情有:
编写自定义标签
定义文件,放在某个
spring.schemas
配置文件,指定
虚拟路径和实际
的映射。我们在
里的都是虚拟路径,如:
&?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
&bean id="otherBean"
class="com.test.OtherBean" scope="prototype"/&
&bean id="myBean"
class="com.test.MyBean" lazy-init="true"/&
&bean id="singletonBean"
class="com.test.SingletonBean"/&
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
就是一个虚拟路径,其对应的真实路径在spring jar包里的META-INF/spring.schemas里面有映射到classpath定义:
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
NamespaceHandler
BeanDefinitionParser
,用于解析自定义的标签,将自定义标签的
解析成一个
BeanDefinition
spring.handlers
配置文件,指定标签命名空间和
为什么要做以上几个事情?我们来看看设计:
对标签解析的设计的过程如下:
文件解析成
文件解析成
树的时候,需要
来验证文件的语法结构。
约定将所有的
的虚拟路径和真是文件路径映射定义在
META-INF/spring.schemas
下面。在容器启动时
会扫描所有的
META-INF/spring.schemas
并将映射维护到一个
spring jar
包里会有自带的标签的
映射,可以看一下部分配置:
http\://www.springframework.org/schema/aop/spring-aop-2.0.xsd
org/springframework/aop/config/spring-aop-2.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-2.5.xsd
org/springframework/aop/config/spring-aop-2.5.xsd
http\://www.springframework.org/schema/aop/spring-aop.xsd
org/springframework/aop/config/spring-aop-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd
org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd
org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd
org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/context/spring-context-2.5.xsd
org/springframework/context/config/spring-context-2.5.xsd
http\://www.springframework.org/schema/context/spring-context.xsd
org/springframework/context/config/spring-context-2.5.xsd
http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd
org/springframework/ejb/config/spring-jee-2.0.xsd
http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd
org/springframework/ejb/config/spring-jee-2.5.xsd
等号左边是虚拟路径,右边是真是路径(classpath下的)。
虚拟路径用在我们的bean定义配置文件里,如:
&beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd&
beans里面的
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
就是个虚拟路径。
BeanDifinition
定义解析成
BeanDefinition
的过程。如果是默认的
会直接进行解析。而如果不是默认的
标签,包括自定义和
等标签,则需要提供专门的
paorser由自己定义和编写,并通过handler注册到容器。Spring
META-INF/spring.handlers
文件,在这里面定义了标签命名空间和
的映射。容器起来的时候会加载
会向容器注册该命名空间下的标签和解析器。在解析的自定义标签的时候,
会根据标签的命名空间和标签名找到一个解析器。由该解析器来完成对该标签内容的解析,并返回一个
BeanDefinition
spring jar
包自带的一些自定义标签扩展的
spring.handlers
文件,可以看到定义了
等其扩展标签的
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/jms=org.springframework.jms.config.JmsNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
META-INF/spring.handlers
看看UtilNamespaceHandler的代码实现
public void init() {
registerBeanDefinitionParser("constant", new ConstantBeanDefinitionParser());
registerBeanDefinitionParser("property-path", new PropertyPathBeanDefinitionParser());
registerBeanDefinitionParser("list", new ListBeanDefinitionParser());
registerBeanDefinitionParser("set", new SetBeanDefinitionParser());
registerBeanDefinitionParser("map", new MapBeanDefinitionParser());
registerBeanDefinitionParser("properties", new PropertiesBeanDefinitionParser());
实现了标签和对应parser的映射注册。
ListBeanDefinitionParser的实现如下:
private static class ListBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
protected Class getBeanClass(Element element) {
return ListFactoryBean.
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String listClass = element.getAttribute("list-class");
List parsedList = parserContext.getDelegate().parseListElement(element, builder.getRawBeanDefinition());
builder.addPropertyValue("sourceList", parsedList);
if (StringUtils.hasText(listClass)) {
builder.addPropertyValue("targetListClass", listClass);
String scope = element.getAttribute(SCOPE_ATTRIBUTE);
if (StringUtils.hasLength(scope)) {
builder.setScope(scope);
这里父类代码不贴了,主要完成的是beanDifinition的生成。
Spring 对于自定义(声明式)bean标签源码实现大概的源码结构如下:
XmlBeanDefinitionReader
是核心类,它接收
容器传给它的资源
文件,由它负责完成整个转换。它调用
DefaultDocumentLoader
树的转换。调用
DefaultBeanDefinitionDocumentReader
BeanDefinition
具体的代码流程细节完全可以基于这个结构去阅读,下面就贴几个核心源码段:
spring.shemas,在PluggableSchemaResolver.java里实现:
public class PluggableSchemaResolver implements EntityResolver {
/***定义schema location的映射文件路径***/
public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
private static final Log logger = LogFactory.getLog(PluggableSchemaResolver.class);
private final ClassLoader classL
private final String schemaMappingsL
/** Stores the mapping of schema URL -& local schema path */
private Properties schemaM
public PluggableSchemaResolver(ClassLoader classLoader) {
this.classLoader = classL
this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION;
public PluggableSchemaResolver(ClassLoader classLoader, String schemaMappingsLocation) {
Assert.hasText(schemaMappingsLocation, "'schemaMappingsLocation' must not be empty");
this.classLoader = classL
this.schemaMappingsLocation = schemaMappingsL
/**==========中间省略部分代码=========**/
/***此处完成schema的加载***/
protected String getSchemaMapping(String systemId) {
if (this.schemaMappings == null) {
if (logger.isDebugEnabled()) {
logger.debug("Loading schema mappings from [" + this.schemaMappingsLocation + "]");
this.schemaMappings =
PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded schema mappings: " + this.schemaMappings);
catch (IOException ex) {
throw new FatalBeanException(
"Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex);
return this.schemaMappings.getProperty(systemId);
spring.handlers,在
DefaultNamespaceHandlerResolver里实现:
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
* The location to look for the mapping files. Can be present in multiple JAR files.
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
/** ClassLoader to use for NamespaceHandler classes */
private final ClassLoader classL
/** Resource location to search for */
private final String handlerMappingsL
/** Stores the mappings from namespace URI to NamespaceHandler class name / instance */
private Map handlerM
public DefaultNamespaceHandlerResolver() {
this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION);
public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {
Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
this.handlerMappingsLocation = handlerMappingsL
/**==========中间省略部分代码=========**/
/************************
* Load the specified NamespaceHandler mappings lazily.
此处加载延迟加载spring.handlers,只有第一次自定义标签被解析到,才会被加载。
****************************/
private Map getHandlerMappings() {
if (this.handlerMappings == null) {
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded mappings [" + mappings + "]");
this.handlerMappings = new HashMap(mappings);
catch (IOException ex) {
IllegalStateException ise = new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]");
ise.initCause(ex);
return this.handlerM
树的解析。
XmlBeanDefinitionReader
doLoadBeanDefinitions
方法里,调用
DefaultDocumentLoader
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
int validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
catch (BeanDefinitionStoreException ex) {
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
getEntityResolver()
会完成spring.schemas的装载,里面会间接调用源码段1。穿进去的entityResolver作为标签解析使用。
Beandifinition:
XmlBeanDefinitionReader
doLoadBeanDefinitions
方法里,调用
BeanDefinitionDocumentReader
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// Support old XmlBeanDefinitionParser SPI for backwards-compatibility.
if (this.parserClass != null) {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
return parser.registerBeanDefinitions(this, doc, resource);
// Read document based on new BeanDefinitionDocumentReader SPI.
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countB
具体细节这里不在累述。
spring标签的扩展性做得还是不错的。在我们公司很多框架的一些通用配置都基于spring的声明式标签来实现。中间的一些约定和设计思想值得学习。
本文很多代码细节没办法累述,有兴趣可以去看看。文章中若有不对的地方请大家指出,一起探讨。
后续的spring源码学习可能会是代理的具体实现,欢迎一起探讨!
论坛回复 /
(20 / 10888)
3.&&&&&& 增加一个 NamespaceHandler 和 BeanDefinitionParser ,用于解析自定义的标签,将自定义标签的 bean 解析成一个 BeanDefinition 返回。对于这一点,其实BeanDefinitionParser 不是必须的,直接在Handler里面解析dom,然后注册到BeanFactory,这样能更清晰地展示Handler的处理逻辑
浏览: 233731 次
来自: 杭州
找不到实现类
NICE,别的博客都是从resouce开始解读的,使我一直不理 ...
xiyuan1025 写道你这是在linux下吗,我在linu ...
项目继承不下来。。
楼主你这个是版本的问题吧。我3.2.3的版本并没有同时持有两个 ...}

我要回帖

更多关于 网络监控安装步骤图解 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信