`
fantaxy025025
  • 浏览: 1251960 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

自定义Spring配置标签

 
阅读更多

推荐直接看第三篇文章和后面的参考文献。

 

=============================================================================

spring 自定义标签 学习 http://blog.csdn.net/ruishenh/article/details/33741501

例子不错,可以看看。

 

=============================================================================

Spring自定义标签 http://zhangxing119.iteye.com/blog/1796906

Spring自定义标签的原理

XML通常通过DTD、XSD定义,但DTD的表达能力较弱,XSD定义则能力比较强,能够定义类型,出现次数等。自定义标签需要XSD支持,在实现时使用Namespace扩展来支持自定义标签。

当你在苦逼的写下面的代码时:

Xml代码  收藏代码
  1. <bean id="beanId" class="com.xxx.xxxx.Xxxxx">  
  2.         <property name="property1">  
  3.             <value>XXXX</value>  
  4.         </property>  
  5.         <property name="property2">  
  6.             <value>XXXX</value>  
  7.         </property>  
  8.     </bean>  

 是不是会羡慕这样写代码呢?

Xml代码  收藏代码
  1. <xxx:xxxx id="beanId"/>  

Spring通过XML解析程序将其解析为DOM树,通过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDefinition。再通过Spring自身的功能对BeanDefinition实例化对象。

在期间,Spring还会加载两项资料:

  • META-INF/spring.handlers 
    指定NamespaceHandler(实现org.springframework.beans.factory.xml.NamespaceHandler)接口,或使用org.springframework.beans.factory.xml.NamespaceHandlerSupport的子类。
  • META-INF/spring.schemas 
    在解析XML文件时将XSD重定向到本地文件,避免在解析XML文件时需要上网下载XSD文件。通过现实org.xml.sax.EntityResolver接口来实现该功能。

=============================================================================

自定义Spring配置标签 http://blog.csdn.net/bingduanlbd/article/details/38770685

引言:

在Sping中,一般使用<bean>这样的元素来配置一个bean,Spring在创建容器的时候会扫描这些配置,根据配置创建对象存放于容器中,然后我们再从容器中取出,或者在配置其他bean的时候作为属性注入。使用bean配置的一个限制是我们必须遵循配置文件的XML Schema定义,这在大多数情况下不会出现问题。但是在一些情况下,我们希望实现更为灵活的bean配置。Spring为此提供了 Custom tag Support,也称为Extensible XML Authoring。通过这个拓展点,我们可以灵活定制自己需要的配置格式。

 

例如,如果我们使用了责任链设计应用程序,那么我们可能希望用下面的方式来配置责任链:

 

[html] view plaincopy
 
  1. <chain id="orderChain" class="foo.bar">  
  2.     <handler> handler1</handler>  
  3.     <hadnler> handler2</handler>  
  4. </chain>  


档Spring创建容器时,扫描到这样的元素的时候,会根据我们事先的定义实例化一个责任链对象,并填充属性。因此,这种特殊的<chain>标签可以作为<bean>标签以外的另一种形式。借助Spring的Custome Tag,我们完全可以实现这样的bean配置。在产品级的应用框架中,可以实现更为复杂的定制标签元素。作为一个入门级别的介绍,我们定义一个用于配置日期格式化的一个类SimpleDateFormat。当然,使用传统的<bean>完全够用,我们这里只是作为例子。

 

 

一个HelloWorld例子:

定制标签的第一步是要定义标签元素的XML结构,也就是采用XSD来元素我们要定制的元素的结构时怎样的。我们定义如下一个简单的XSD:

 

[html] view plaincopy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <xsd:schema xmlns="http://www.mycompany.com/schema/myns"  
  3.         xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
  4.         xmlns:beans="http://www.springframework.org/schema/beans"  
  5.         targetNamespace="http://www.mycompany.com/schema/myns"  
  6.         elementFormDefault="qualified"  
  7.         attributeFormDefault="unqualified">  
  8.   
  9.     <xsd:import namespace="http://www.springframework.org/schema/beans"/>  
  10.   
  11.     <xsd:element name="dateformat">  
  12.         <xsd:complexType>  
  13.             <xsd:complexContent>  
  14.                 <xsd:extension base="beans:identifiedType">  
  15.                     <xsd:attribute name="lenient" type="xsd:boolean"/>  
  16.                     <xsd:attribute name="pattern" type="xsd:string" use="required"/>  
  17.                 </xsd:extension>  
  18.             </xsd:complexContent>  
  19.         </xsd:complexType>  
  20.     </xsd:element>  
  21. </xsd:schema>  

在这个XSD定义中,有一个标签叫dateformat,这就是我们用来替换bean标签的自定义标签。注意到我们导入了Spring本身的beans命名空间,并且在beans:identifiedType基础之上定义dateformat标签。也就是我们这个标签可以像<bean>标签一样拥有id属性。同时我们增加了两个属性lenient和pattern。这有点继承的味道。

 

 

定义完XSD之后,我们要告诉Spring遇到这样的标记(命名空间+元素名称)时,如何创建对象。Spring中,完成这个任务的是NamespaceHandler。因此我们需要提供一个NamespaceHandler实现来处理自定义的<dateformat>标签元素。一个简单的实现如下:

 

[java] view plaincopy
 
  1. package extensiblexml.customtag;  
  2.   
  3. import org.springframework.beans.factory.xml.NamespaceHandlerSupport;  
  4.   
  5. public class MyNamespaceHandler extends NamespaceHandlerSupport {  
  6.   
  7.     public void init() {  
  8.         registerBeanDefinitionParser("dateformat",  
  9.                 new SimpleDateFormatBeanDefinitionParser());  
  10.     }  
  11.   
  12. }  


我们在初始化方法中注册了一个Bean定义的解析器,这个解析器就是用来解析定制的配置标签的。其实现如下:

 

 

[java] view plaincopy
 
  1. package extensiblexml.customtag;  
  2.   
  3. import org.springframework.beans.factory.support.BeanDefinitionBuilder;  
  4. import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;  
  5. import org.springframework.util.StringUtils;  
  6. import org.w3c.dom.Element;  
  7.   
  8. import java.text.SimpleDateFormat;  
  9.   
  10. public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {   
  11.   
  12.     protected Class<SimpleDateFormat> getBeanClass(Element element) {  
  13.         return SimpleDateFormat.class;   
  14.     }  
  15.   
  16.     @SuppressWarnings("deprecation")  
  17.     protected void doParse(Element element, BeanDefinitionBuilder bean) {  
  18.         // this will never be null since the schema explicitly requires that a value be supplied  
  19.         String pattern = element.getAttribute("pattern");  
  20.         bean.addConstructorArg(pattern);  
  21.   
  22.         // this however is an optional property  
  23.         String lenient = element.getAttribute("lenient");  
  24.         if (StringUtils.hasText(lenient)) {  
  25.             bean.addPropertyValue("lenient", Boolean.valueOf(lenient));  
  26.         }  
  27.     }  
  28.   
  29. }  


这个解析器的doParse中,实现了解析的具体逻辑,借助Spring提供的支持类,我们可以很轻松地完成解析。以上三个文件放在同一个目录下,即把XSD文件跟Java代码放在同一目录。编码完毕之后,还需要做一些配置工作。我们必须告诉Spring我们准备使用自定义的标签元素,告诉Spring如何解析元素,否则Spring没那么聪明。这里需要2个配置文件,在与代码根路径同一级别下,床垫一个叫META-INF的文件。并在里面创建名为spring.handlers和spring.schemas,用于告诉Spring自定义标签的文档结构以及解析它的类。两个文件内容分别如下:

 

spring.handlers:

 

[html] view plaincopy
 
  1. http\://www.mycompany.com/schema/myns=extensiblexml.customtag.MyNamespaceHandler  

等号的左边是XSD定义中的targetNamespace属性,右边是NamespaceHandler的全称限定名。

 

spring.schemas:

 

 

[html] view plaincopy
 
  1. http\://www.mycompany.com/schema/myns/myns.xsd=extensiblexml/customtag/myns.xsd  

 

 

然后像往常一样配置bean,作为简单的测试,我们定义一个bean:

 

[html] view plaincopy
 
  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" xmlns:myns="http://www.mycompany.com/schema/myns"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  5.         http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd" >  
  6.   
  7.     <myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm"  
  8.         lenient="true" />  
  9. </beans>  


在Eclipse中,整个项目结构如下图:

 

 

最后我们写个测试类测试一下能否工作:

 

[java] view plaincopy
 
  1. package extensiblexml.customtag;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Date;  
  5.   
  6. import org.springframework.context.ApplicationContext;  
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  8.   
  9. public class Test {  
  10.   
  11.     public static void main(String[] args) {  
  12.         ApplicationContext context = new ClassPathXmlApplicationContext(  
  13.                 "beans.xml");  
  14.         SimpleDateFormat format = (SimpleDateFormat) context  
  15.                 .getBean("defaultDateFormat");  
  16.         System.out.println(format.format(new Date()));  
  17.   
  18.     }  
  19.   
  20. }  


一切正常,输出如下:

 

 

更实用的例子

第一个例子主要是为了举例,在实际中用处不大,我们接着来看一个更复杂的自定义标签。我们自定义一个<fileList>标签,当Spring扫描到这个标签的时候,创建一个指定目录下的File类的集合。另外,可以使用<fileFilter>对该目录的文件进行过滤。如下:

 

[java] view plaincopy
 
  1. <core-commons:fileList id="xmlList" directory="src/extensiblexml/example">  
  2.     <core-commons:fileFilter>  
  3.     <bean class="org.apache.commons.io.filefilter.RegexFileFilter">  
  4.         <constructor-arg value=".*.java" />  
  5.     </bean>  
  6.     </core-commons:fileFilter>  
  7. </core-commons:fileList>  

上面的bean定义中,我们从“src/extensible/example”目录中筛选出java源码文件。

 

使用下面的测试迭代输出文件名:

 

[java] view plaincopy
 
  1. @SuppressWarnings("unchecked")  
  2. List<File> fileList = (List<File>) context.getBean("xmlList");  
  3. for (File file : fileList) {  
  4.     System.out.println(file.getName());  
  5. }  

输出结果如下:

 

根据第一个例子中的步骤,各部分配置及代码如下:

core-commons-1.0.xsd:

 

[html] view plaincopy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <xsd:schema xmlns="http://www.example.com/schema/core-commons-1.0"  
  3.     targetNamespace="http://www.example.com/schema/core-commons-1.0"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
  6.     xmlns:beans="http://www.springframework.org/schema/beans"  
  7.     elementFormDefault="qualified"  
  8.     attributeFormDefault="unqualified"  
  9.     version="1.0">  
  10.   
  11.     <xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"/>  
  12.   
  13.     <xsd:element name="fileList">  
  14.         <xsd:complexType>  
  15.             <xsd:complexContent>  
  16.                 <xsd:extension base="beans:identifiedType">  
  17.                     <xsd:sequence>  
  18.                         <xsd:element ref="fileFilter" minOccurs="0" maxOccurs="1"/>  
  19.                         <xsd:element ref="fileList" minOccurs="0" maxOccurs="unbounded"/>  
  20.                     </xsd:sequence>  
  21.                     <xsd:attribute name="directory" type="xsd:string"/>  
  22.                     <xsd:attribute name="scope" type="xsd:string"/>  
  23.                 </xsd:extension>  
  24.             </xsd:complexContent>  
  25.         </xsd:complexType>  
  26.     </xsd:element>  
  27.   
  28.     <xsd:element name="fileFilter">  
  29.         <xsd:complexType>  
  30.             <xsd:complexContent>  
  31.                 <xsd:extension base="beans:identifiedType">  
  32.                     <xsd:group ref="limitedType"/>  
  33.                     <xsd:attribute name="scope" type="xsd:string"/>  
  34.                 </xsd:extension>  
  35.             </xsd:complexContent>  
  36.         </xsd:complexType>  
  37.     </xsd:element>  
  38.   
  39.     <xsd:group name="limitedType">  
  40.         <xsd:sequence>  
  41.             <xsd:choice minOccurs="1" maxOccurs="unbounded">  
  42.                 <xsd:element ref="beans:bean"/>  
  43.                 <xsd:element ref="beans:ref"/>  
  44.                 <xsd:element ref="beans:idref"/>  
  45.                 <xsd:element ref="beans:value"/>  
  46.                 <xsd:any minOccurs="0"/>  
  47.             </xsd:choice>  
  48.         </xsd:sequence>  
  49.     </xsd:group>  
  50. </xsd:schema>  


CoreNamespaceHandler.java:

 

 

[java] view plaincopy
 
  1. package extensiblexml.example;  
  2.   
  3. import org.springframework.beans.factory.xml.NamespaceHandlerSupport;  
  4.   
  5. public class CoreNamespaceHandler  
  6.     extends NamespaceHandlerSupport  
  7. {  
  8.   
  9.     @Override  
  10.     public void init() {  
  11.         this.registerBeanDefinitionParser("fileList"new FileListDefinitionParser());  
  12.         this.registerBeanDefinitionParser("fileFilter"new FileFilterDefinitionParser());  
  13.     }  
  14. }  


FileListDefinitionParser.java:

 

 

[java] view plaincopy
 
  1. public class FileListDefinitionParser  
  2.     extends AbstractSingleBeanDefinitionParser  
  3. {  
  4.   
  5.     /** 
  6.      * The bean that is created for this tag element 
  7.      * 
  8.      * @param element The tag element 
  9.      * @return A FileListFactoryBean 
  10.      */  
  11.     @Override  
  12.     protected Class<?> getBeanClass(Element element) {  
  13.         return FileListFactoryBean.class;  
  14.     }  
  15.   
  16.     /** 
  17.      * Called when the fileList tag is to be parsed 
  18.      * 
  19.      * @param element The tag element 
  20.      * @param ctx The context in which the parsing is occuring 
  21.      * @param builder The bean definitions build to use 
  22.      */  
  23.     @Override  
  24.     protected void doParse(Element element, ParserContext ctx, BeanDefinitionBuilder builder) {  
  25.         // Set the directory property  
  26.         builder.addPropertyValue("directory", element.getAttribute("directory"));  
  27.   
  28.         // Set the scope  
  29.         builder.setScope(element.getAttribute("scope"));  
  30.   
  31.         // We want any parsing to occur as a child of this tag so we need to make  
  32.         // a new one that has this as it's owner/parent  
  33.         ParserContext nestedCtx = new ParserContext(ctx.getReaderContext(), ctx.getDelegate(), builder.getBeanDefinition());  
  34.   
  35.         // Support for filters  
  36.         Element exclusionElem = DomUtils.getChildElementByTagName(element, "fileFilter");  
  37.         if (exclusionElem != null) {  
  38.             // Just make a new Parser for each one and let the parser do the work  
  39.             FileFilterDefinitionParser ff = new FileFilterDefinitionParser();  
  40.             builder.addPropertyValue("filters", ff.parse(exclusionElem, nestedCtx));  
  41.         }  
  42.   
  43.         // Support for nested fileList  
  44.         List<Element> fileLists = DomUtils.getChildElementsByTagName(element, "fileList");  
  45.         // Any objects that created will be placed in a ManagedList  
  46.         // so Spring does the bulk of the resolution work for us  
  47.         ManagedList<Object> nestedFiles = new ManagedList<Object>();  
  48.         if (fileLists.size() > 0) {  
  49.             // Just make a new Parser for each one and let them do the work  
  50.             FileListDefinitionParser fldp = new FileListDefinitionParser();  
  51.             for (Element fileListElem : fileLists) {  
  52.                 nestedFiles.add(fldp.parse(fileListElem, nestedCtx));  
  53.             }  
  54.         }  
  55.   
  56.         // Support for other tags that return File (value will be converted to file)  
  57.         try {  
  58.             // Go through any other tags we may find.  This does not mean we support  
  59.             // any tag, we support only what parseLimitedList will process  
  60.             NodeList nl = element.getChildNodes();  
  61.             for (int i=0; i<nl.getLength(); i++) {  
  62.                 // Parse each child tag we find in the correct scope but we  
  63.                 // won't support custom tags at this point as it coudl destablize things  
  64.                 DefinitionParserUtil.parseLimitedList(nestedFiles, nl.item(i), ctx,  
  65.                     builder.getBeanDefinition(), element.getAttribute("scope"), false);  
  66.             }  
  67.         }  
  68.         catch (Exception e) {  
  69.             throw new RuntimeException(e);  
  70.         }  
  71.   
  72.         // Set the nestedFiles in the properties so it is set on the FactoryBean  
  73.         builder.addPropertyValue("nestedFiles", nestedFiles);  
  74.   
  75.     }  
  76.   
  77.     public static class FileListFactoryBean  
  78.         implements FactoryBean<Collection<File>>  
  79.     {  
  80.   
  81.         String directory;  
  82.         private Collection<FileFilter> filters;  
  83.         private Collection<File> nestedFiles;  
  84.   
  85.         @Override  
  86.         public Collection<File> getObject() throws Exception {  
  87.             // These can be an array list because the directory will have unique's and the nested is already only unique's  
  88.             Collection<File> files = new ArrayList<File>();  
  89.             Collection<File> results = new ArrayList<File>(0);  
  90.   
  91.             if (directory != null) {  
  92.                 // get all the files in the directory  
  93.                 File dir = new File(directory);  
  94.                 File[] dirFiles = dir.listFiles();  
  95.                 if (dirFiles != null) {  
  96.                     files = Arrays.asList(dirFiles);  
  97.                 }  
  98.             }  
  99.   
  100.             // If there are any files that were created from the nested tags,  
  101.             // add those to the list of files  
  102.             if (nestedFiles != null) {  
  103.                 files.addAll(nestedFiles);  
  104.             }  
  105.   
  106.             // If there are filters we need to go through each filter  
  107.             // and see if the files in the list pass the filters.  
  108.             // If the files does not pass any one of the filters then it  
  109.             // will not be included in the list  
  110.             if (filters != null) {  
  111.                 boolean add;  
  112.                 for (File f : files) {  
  113.                     add = true;  
  114.                     for (FileFilter ff : filters) {  
  115.                         if (!ff.accept(f)) {  
  116.                             add = false;  
  117.                             break;  
  118.                         }  
  119.                     }  
  120.                     if (add) results.add(f);  
  121.                 }  
  122.                 return results;  
  123.             }  
  124.   
  125.             return files;  
  126.         }  
  127.   
  128.         @Override  
  129.         public Class<?> getObjectType() {  
  130.             return Collection.class;  
  131.         }  
  132.   
  133.         @Override  
  134.         public boolean isSingleton() {  
  135.             return false;  
  136.         }  
  137.   
  138.         public void setDirectory(String dir) {  
  139.             this.directory = dir;  
  140.         }  
  141.   
  142.         public void setFilters(Collection<FileFilter> filters) {  
  143.             this.filters = filters;  
  144.         }  
  145.   
  146.         /** 
  147.          * What we actually get from the processing of the nested tags 
  148.          * is a collection of files within a collection so we flatten it and 
  149.          * only keep the uniques 
  150.          */  
  151.         public void setNestedFiles(Collection<Collection<File>> nestedFiles) {  
  152.             this.nestedFiles = new HashSet<File>(); // keep the list unique  
  153.             for (Collection<File> nested : nestedFiles) {  
  154.                 this.nestedFiles.addAll(nested);  
  155.             }  
  156.         }  
  157.   
  158.     }  
  159. }  


FileFilterDefinitionParser.java

 

 

[java] view plaincopy
 
  1. public class FileFilterDefinitionParser  
  2.     extends AbstractSingleBeanDefinitionParser  
  3. {  
  4.   
  5.     /** 
  6.      * The bean that is created for this tag element 
  7.      * 
  8.      * @param element The tag element 
  9.      * @return A FileFilterFactoryBean 
  10.      */  
  11.     @Override  
  12.     protected Class<?> getBeanClass(Element element) {  
  13.         return FileFilterFactoryBean.class;  
  14.     }  
  15.   
  16.     /** 
  17.      * Called when the fileFilter tag is to be parsed 
  18.      * 
  19.      * @param element The tag element 
  20.      * @param ctx The context in which the parsing is occuring 
  21.      * @param builder The bean definitions build to use 
  22.      */  
  23.     @Override  
  24.     protected void doParse(Element element, ParserContext ctx, BeanDefinitionBuilder builder) {  
  25.   
  26.         // Set the scope  
  27.         builder.setScope(element.getAttribute("scope"));  
  28.   
  29.         try {  
  30.             // All of the filters will eventually end up in this list  
  31.             // We use a 'ManagedList' and not a regular list because anything  
  32.             // placed in a ManagedList object will support all of Springs  
  33.             // functionalities and scopes for us, we dont' have to code anything  
  34.             // in terms of reference lookups, EL, etc  
  35.             ManagedList<Object> filters = new ManagedList<Object>();  
  36.   
  37.             // For each child node of the fileFilter tag, parse it and place it  
  38.             // in the filtes list  
  39.             NodeList nl = element.getChildNodes();  
  40.             for (int i=0; i<nl.getLength(); i++) {  
  41.                 DefinitionParserUtil.parseLimitedList(filters, nl.item(i), ctx, builder.getBeanDefinition(), element.getAttribute("scope"));  
  42.             }  
  43.   
  44.             // Add the filtes to the list of properties (this is applied  
  45.             // to the factory beans setFilters below)  
  46.             builder.addPropertyValue("filters", filters);  
  47.         }  
  48.         catch (Exception e) {  
  49.             throw new RuntimeException(e);  
  50.         }  
  51.     }  
  52.   
  53.     public static class FileFilterFactoryBean  
  54.         implements FactoryBean<Collection<FileFilter>>  
  55.     {  
  56.   
  57.         private final List<FileFilter> filters = new ArrayList<FileFilter>();  
  58.   
  59.         @Override  
  60.         public Collection<FileFilter> getObject() throws Exception {  
  61.             return filters;  
  62.         }  
  63.   
  64.         @Override  
  65.         public Class<?> getObjectType() {  
  66.             return Collection.class;  
  67.         }  
  68.   
  69.         @Override  
  70.         public boolean isSingleton() {  
  71.             return false;  
  72.         }  
  73.   
  74.         /** 
  75.          * Go through the list of filters and convert the String ones 
  76.          * (the ones that were set with <value> and make them NameFileFilters 
  77.          */  
  78.         public void setFilters(Collection<Object> filterList) {  
  79.             for (Object o : filterList) {  
  80.                 if (o instanceof String) {  
  81.                     filters.add(new NameFileFilter(o.toString()));  
  82.                 }  
  83.                 else if (o instanceof FileFilter) {  
  84.                     filters.add((FileFilter)o);  
  85.                 }  
  86.             }  
  87.         }  
  88.   
  89.     }  
  90. }  


DefinitionParserUtil.java:

 

 

[java] view plaincopy
 
  1. package extensiblexml.example;  
  2.   
  3. import org.springframework.beans.factory.config.BeanDefinition;  
  4. import org.springframework.beans.factory.config.BeanDefinitionHolder;  
  5. import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;  
  6. import org.springframework.beans.factory.support.DefaultListableBeanFactory;  
  7. import org.springframework.beans.factory.support.ManagedList;  
  8. import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;  
  9. import org.springframework.beans.factory.xml.ParserContext;  
  10. import org.springframework.expression.Expression;  
  11. import org.springframework.expression.ExpressionParser;  
  12. import org.springframework.expression.spel.standard.SpelExpressionParser;  
  13. import org.w3c.dom.Element;  
  14. import org.w3c.dom.Node;  
  15.   
  16. public class DefinitionParserUtil {  
  17.   
  18.     /** 
  19.      * Parses the children of the passed in ParentNode for the following tags: 
  20.      * <br/> 
  21.      * value 
  22.      * ref 
  23.      * idref 
  24.      * bean 
  25.      * property 
  26.      * *custom* 
  27.      * <p/> 
  28.      * 
  29.      * The value tag works with Spring EL even in a Spring Batch scope="step" 
  30.      * 
  31.      * @param objects The list of resultings objects from the parsing (passed in for recursion purposes) 
  32.      * @param parentNode The node who's children should be parsed 
  33.      * @param ctx The ParserContext to use 
  34.      * @param parentBean The BeanDefinition of the bean who is the parent of the parsed bean 
  35.      *      (i.e. the Bean that is the parentNode) 
  36.      * @param scope The scope to execute in.  Checked if 'step' to provide Spring EL 
  37.      *      support in a Spring Batch env 
  38.      * @throws Exception 
  39.      */  
  40.     public static void parseLimitedList(ManagedList<Object> objects, Node node,  
  41.         ParserContext ctx, BeanDefinition parentBean, String scope)  
  42.         throws Exception  
  43.     {  
  44.         parseLimitedList(objects, node, ctx, parentBean, scope, true);  
  45.     }  
  46.   
  47.     /** 
  48.      * Parses the children of the passed in ParentNode for the following tags: 
  49.      * <br/> 
  50.      * value 
  51.      * ref 
  52.      * idref 
  53.      * bean 
  54.      * property 
  55.      * *custom* 
  56.      * <p/> 
  57.      * 
  58.      * The value tag works with Spring EL even in a Spring Batch scope="step" 
  59.      * 
  60.      * @param objects The list of resultings objects from the parsing (passed in for recursion purposes) 
  61.      * @param parentNode The node who's children should be parsed 
  62.      * @param ctx The ParserContext to use 
  63.      * @param parentBean The BeanDefinition of the bean who is the parent of the parsed bean 
  64.      *      (i.e. the Bean that is the parentNode) 
  65.      * @param scope The scope to execute in.  Checked if 'step' to provide Spring EL 
  66.      *      support in a Spring Batch env 
  67.      * @param supportCustomTags Should we support custom tags within our tags? 
  68.      * @throws Exception 
  69.      */  
  70.     @SuppressWarnings("deprecation")  
  71.     public static void parseLimitedList(ManagedList<Object> objects, Node node,  
  72.         ParserContext ctx, BeanDefinition parentBean, String scope, boolean supportCustomTags)  
  73.         throws Exception  
  74.     {  
  75.         // Only worry about element nodes  
  76.         if (node.getNodeType() == Node.ELEMENT_NODE) {  
  77.             Element elem = (Element)node;  
  78.             String tagName = node.getLocalName();  
  79.   
  80.             if (tagName.equals("value")) {  
  81.                 String val = node.getTextContent();  
  82.                 // to get around an issue with Spring Batch not parsing Spring EL  
  83.                 // we will do it for them  
  84.                 if (scope.equals("step")  
  85.                     && (val.startsWith("#{") && val.endsWith("}"))  
  86.                     && (!val.startsWith("#{jobParameters"))  
  87.                     )  
  88.                 {  
  89.                     // Set up a new EL parser  
  90.                     ExpressionParser parser = new SpelExpressionParser();  
  91.                     // Parse the value  
  92.                     Expression exp = parser.parseExpression(val.substring(2, val.length()-1));  
  93.                     // Place the results in the list of created objects  
  94.                     objects.add(exp.getValue());  
  95.                 }  
  96.                 else {  
  97.                     // Otherwise, just treat it as a normal value tag  
  98.                     objects.add(val);  
  99.                 }  
  100.             }  
  101.             // Either of these is a just a lookup of an existing bean  
  102.             else if (tagName.equals("ref") || tagName.equals("idref")) {  
  103.                 objects.add(ctx.getRegistry().getBeanDefinition(node.getTextContent()));  
  104.             }  
  105.             // We need to create the bean  
  106.             else if (tagName.equals("bean")) {  
  107.                 // There is no quick little util I could find to create a bean  
  108.                 // on the fly programmatically in Spring and still support all  
  109.                 // Spring functionality so basically I mimic what Spring actually  
  110.                 // does but on a smaller scale.  Everything Spring allows is  
  111.                 // still supported  
  112.   
  113.                 // Create a factory to make the bean  
  114.                 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();  
  115.                 // Set up a parser for the bean  
  116.                 BeanDefinitionParserDelegate pd = new BeanDefinitionParserDelegate(ctx.getReaderContext());  
  117.                 // Parse the bean get its information, now in a DefintionHolder  
  118.                 BeanDefinitionHolder bh = pd.parseBeanDefinitionElement(elem, parentBean);  
  119.                 // Register the bean will all the other beans Spring is aware of  
  120.                 BeanDefinitionReaderUtils.registerBeanDefinition(bh, beanFactory);  
  121.                 // Get the bean from the factory.  This will allows Spring  
  122.                 // to do all its work (EL processing, scope, etc) and give us  
  123.                 // the actual bean itself  
  124.                 Object bean = beanFactory.getBean(bh.getBeanName());  
  125.                 objects.add(bean);  
  126.             }  
  127.             /* 
  128.              * This is handled a bit differently in that it actually sets the property 
  129.              * on the parent bean for us based on the property 
  130.              */  
  131.             else if (tagName.equals("property")) {  
  132.                 BeanDefinitionParserDelegate pd = new BeanDefinitionParserDelegate(ctx.getReaderContext());  
  133.                 // This method actually set eh property on the parentBean for us so  
  134.                 // we don't have to add anything to the objects object  
  135.                 pd.parsePropertyElement(elem, parentBean);  
  136.             }  
  137.             else if (supportCustomTags) {  
  138.                 // handle custom tag  
  139.                 BeanDefinitionParserDelegate pd = new BeanDefinitionParserDelegate(ctx.getReaderContext());  
  140.                 BeanDefinition bd = pd.parseCustomElement(elem, parentBean);  
  141.                 objects.add(bd);  
  142.             }  
  143.         }  
  144.     }  
  145. }  


spring.schemas

 

 

[html] view plaincopy
 
  1. http\://www.mycompany.com/schema/myns/myns.xsd=extensiblexml/customtag/myns.xsd  
  2. http\://www.example.com/schema/core-commons-1.0.xsd=extensiblexml/example/core-commons-1.0.xsd  


spring.handlers

 

 

[html] view plaincopy
 
  1. http\://www.mycompany.com/schema/myns=extensiblexml.customtag.MyNamespaceHandler  
  2. http\://www.example.com/schema/core-commons-1.0=extensiblexml.example.CoreNamespaceHandler  



 

小结:

要自定义Spring的配置标签,需要一下几个步骤:

**使用XSD定义XML配置中标签元素的结构(myns.XSD)

**提供该XSD命名空间的处理类,它可以处理多个标签定义(MyNamespaceHandler.java)

**为每个标签元素的定义提供解析类。(SimpleDateFormatBeanDefinitionParser.java)

**两个特殊文件通知Spring使用自定义标签元素(spring.handlers 和spring.schemas)

 

参考资料:

Spring官方的Extensible XML Authoring文档:

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/extensible-xml.html

一个不错的教程:

http://sloanseaman.com/wordpress/2012/03/26/spring-custom-tags-extensible-xml-part-1/

http://sloanseaman.com/wordpress/2012/04/08/spring-custom-tags-extensible-xml-part-2/

 

转载请注明出处。

 

 

+

+

+

=

+

+

+

分享到:
评论

相关推荐

    Spring自定义配置文件便签[Maven]工程可运行

    Spring5.0自定义配置文件便签[Maven]工程可运行【spring-customize-tag】

    spring自定义标签

    扩展Spring, 自定义标签的实现, 包括 schema配置和自定义标签以及handler的加载过程

    基于Spring开发之自定义标签及其解析

    Spring框架是现在Java最流行的开源框架之一,需要实现一些自定义的标签,主要是方便使用我们框架的人能够快速、简单进行配置,有兴趣的可以了解一下。

    SpringAll_wuyouzhuguli.tar.gz

    自定义Spring Boot 内容协商 Spring Boot 中处理跨域 Spring Boot 中的异步调用 Spring Boot 整合Kafka Spring Boot整合Mongo DB Spring Boot 2.0 WebFlux编程 Spring Boot WebFlux增删改查样例 二、Spring Boot & ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    配置标签库 13.9.2. form标签 13.9.3. input标签 13.9.4. checkbox标签 13.9.5. radiobutton标签 13.9.6. password标签 13.9.7. select标签 13.9.8. option标签 13.9.9. options标签 13.9.10. textarea标签 13.9.11...

    Spring 2.0 开发参考手册

    配置标签库 13.9.2. form标签 13.9.3. input标签 13.9.4. checkbox标签 13.9.5. radiobutton标签 13.9.6. password标签 13.9.7. select标签 13.9.8. option标签 13.9.9. options标签 13.9.10. textarea...

    4、Spring Security 安全权限管理手册

    1、区分Authentication(验证)与 Authorization(授权) ...7、Spring配置文件中设置命名空间 8、通过数据库验证用户身份 9、完善web页面验证规则 10、自定义验证配置 11、本地化消息输出(国际化)

    Spring中文帮助文档

    2.5.4. Spring MVC的表单标签库 2.5.5. 对Tiles 2 支持 2.5.6. 对JSF 1.2支持 2.5.7. JAX-WS支持 2.6. 其他 2.6.1. 动态语言支持 2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文...

    最详细Spring Security学习资料(源码)

    Spring Security是一个功能强大且高度可定制的身份验证和授权框架,专门用于保护Java应用程序的...Web集成:Spring Security能够无缝集成到Spring框架和Spring MVC中,提供了过滤器、标签库等工具,简化了权限控制和

    spring chm文档

    配置标签库 13.9.2. form标签 13.9.3. input标签 13.9.4. checkbox标签 13.9.5. radiobutton标签 13.9.6. password标签 13.9.7. select标签 13.9.8. option标签 13.9.9. options标签 13.9.10. textarea...

    Spring API

    2.5.4. Spring MVC的表单标签库 2.5.5. 对Tiles 2 支持 2.5.6. 对JSF 1.2支持 2.5.7. JAX-WS支持 2.6. 其他 2.6.1. 动态语言支持 2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文...

    Spring IOC Bean标签属性介绍(教学视频+源代码)

    Spring IOC Bean标签属性介绍 0.Bean标签属性介绍 1.0 新建一个Maven工程 1.1 pom.xml 1.2 实体类JavaBean 1.2.1 User类 1.3 当Scope="singleton"时 1.4 当 Scope="singleton" 且 lazy-init="true" 时 1.5 当scope=...

    spring security 参考手册中文版

    38. Spring Data&Spring安全配置 273 39. @Query中的安全表达式 273 第八部分 附录 274 40.安全数据库模式 274 40.1用户模式 274 40.1.1集团当局 274 40.2持久登录(记得我)架构 275 40.3 ACL模式 275 40.3.1 ...

    SpringBoot下的SpringAOP-day04-源代码

    SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法 1.动态代理总结 1.1 JDK动态代理特点 1.2 CGlib动态代理 1.2.1 CGLib特点说明 1.3 动态代理的作用 2 Spring...

    spring security 安全权限管理手册

    1、搭建基本的Spring Security项目 2、使用数据库管理用户权限 3、自定义认证数据库表结构 ... 配置Spring Security 为CAS配置SSL 10、标签的使用 11、自动登录 12、防御会话伪造 13、切换用户 14、集成jcaptcha

    基于Spring MVC的web框架 1.1.11

    工具类数据校验 jsp自定义标签 Spring自定义注解 默认requestMapping 1.1.2 代码生成器 1.1.3 首页修改 dateformat.js 时间参数转换 SpringMVC配置文件集中 快递参数接口 1.1.4 des加解密字符串和文件 1.1.5 redis...

    轻松实现基于JPA的库SpringDataJPA.zip

    Spring Data JPA 的目标是通过让一些必须的工作变得更简单,来显著提高数据访问层的实现。作为一个开发者,你写你的仓库界面,包括自定义查询方法,而 Spring 给你提供自动实现。特性对建立基于Spring ... 标签:Spring

    Spring Security 中文教程.pdf

    Spring Bean配置 19.4.6. LDAP属性和自定义UserDetails 20. JSP标签库 20.1. 声明Taglib 20.2. authorize 标签 20.3. authentication 标签 20.4. accesscontrollist 标签 21. Java认证和授权服务...

    xbeanspring-2.6.jar

    我一直坚持xml是人机共享的信道, 应该是人与机器都能够... 在witrix平台的配置文件中, 我们大量使用了tpl模板技术, 通过tpl的自定义标签机制对外提供一些Domain Specific的功能标签, 大大增强了xml标签的语义表达能力.

    spring2.5 struts2.0 hibernate3.2.5 搭建的企业级开发基础模块

    哦 忘记介绍了, 当中还有本人写的几个自定义标签:com.light.framework.tag 自定义标签的帮助类:com.light.framework.tagAssistant 还有登录拦截器:com.light.framework.interceptor 字符集过滤器:...

Global site tag (gtag.js) - Google Analytics