`
fantaxy025025
  • 浏览: 1311488 次
  • 性别: 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自定义标签例子

    通过研究这个例子,我们可以学习到如何将业务逻辑抽象出来,封装成自定义标签,使Spring配置更加简洁。这对于大型项目来说尤其重要,因为它可以提高代码的可读性和模块化程度。 此外,理解自定义标签的工作原理还能...

    spring 自定义xml标签

    总之,自定义Spring XML标签是一项强大的功能,它允许开发者按照项目特性定制配置语法,提高代码的可读性和可维护性。通过实现`NamespaceHandler`和`BeanDefinitionParser`,我们可以轻松地将业务逻辑融入到Spring的...

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

    在Spring框架中,自定义配置文件和标签是提高代码可读性和灵活性的重要手段。这个名为"Spring自定义配置文件便签[Maven]工程可运行"的项目,显然是一个基于Maven构建的Spring 5.0应用程序,它包含了自定义配置文件和...

    spring-boot 自定义xml配置web请求拦截器

    自定义XML配置通常会涉及到Spring的`&lt;beans&gt;`标签和`&lt;bean&gt;`标签,用于声明和实例化对象。在XML中定义拦截器,我们需要创建一个实现了`HandlerInterceptor`接口的类,并在XML配置文件中声明这个类。然后,我们可以...

    spring mvc freemarker 自定义标签

    然后,你需要在Spring配置中注册这个自定义标签。在`WebMvcConfigurer`的实现中,添加`freemarkerConfiguration` bean,并使用`freemarkerConfigurer`的`setCustomTags`方法添加自定义标签: ```java @...

    Spring 5.2.9 06 源码分析-spring自定义标签解析过程

    在Spring框架中,自定义标签解析是扩展Spring配置能力的重要方式。通过自定义标签,开发者可以创建更加符合业务逻辑和可读性强的XML配置文件。本文将深入剖析Spring 5.2.9版本中自定义标签的解析过程,旨在帮助读者...

    spring自定义标签

    在Spring框架中,自定义标签是一项非常实用的功能,它允许我们创建自己的XML标签来简化配置,提高代码可读性,并实现特定的业务逻辑。本文将深入探讨Spring自定义标签的概念、实现过程及其在实际开发中的应用。 ...

    自定义 Schema 解析 Spring Bean

    通过定义自定义Schema,我们可以限制或扩展Spring配置文件中可用的元素和属性,确保配置的正确性和一致性。 实现自定义Schema解析的过程主要包括以下几个步骤: 1. **定义Schema**: 使用XSD(XML Schema ...

    spring-扩展点-namespacehandler(Spring自定义标签)

    当我们需要在Spring配置文件中引入自定义标签时,`NamespaceHandler`起着至关重要的作用。这篇博文通过分析`spring-web-namespacehandler`,将深入探讨这一主题。 首先,`NamespaceHandler`是Spring框架解析XML配置...

    06 源码分析-spring自定义标签解析过程

    在Spring框架中,自定义标签的解析过程是一个关键的组件,它使得开发者能够通过XML配置文件以更加直观和简洁的方式声明Bean的定义。本节将深入探讨Spring 5.2.9版本中自定义标签的解析机制,以及背后的源码实现。 ...

    这一次搞懂Spring自定义标签以及注解解析原理说明

    在Spring框架中,自定义标签和注解解析是两个关键的特性,它们使得代码与配置的集成更加紧密,简化了应用程序的开发。本篇文章将深入探讨Spring如何处理这两种类型的元数据。 首先,让我们来理解Spring如何解析...

    这一次搞懂Spring自定义标签以及注解解析原理说明.docx

    在Spring框架中,自定义标签和注解解析是核心功能之一,它们允许开发者根据特定需求扩展和定制Spring的配置方式。本文将深入探讨这两个概念的解析原理,帮助读者理解Spring如何处理自定义标签和注解。 首先,让我们...

    SpringBoot中自定义日志配置logback-spring.xml示例源码

    本教程将详细介绍如何在Spring Boot中自定义日志配置,特别是通过`logback-spring.xml`文件来实现。 首先,我们需要理解`logback-spring.xml`与传统的`logback.xml`的区别。`logback-spring.xml`是专门为Spring ...

    spring 自定义属性编辑器

    - 配置文件注册:在Spring的XML配置文件中,通过`&lt;bean&gt;`标签的`property-editorRegistrar`属性指定一个实现了`PropertyEditorRegistrar`接口的类。在该类的`registerEditors()`方法中,可以使用`...

    自定义分页标签struts2,spring

    本项目"自定义分页标签struts2,spring"是针对Struts2和Spring框架的一个自定义标签实现,旨在简化开发过程,提高代码的可复用性和可维护性。下面我们将详细探讨这个项目中的关键技术点。 首先,Struts2是一个非常...

    自定义xml标签

    在Spring框架中,自定义XML标签是扩展Spring配置能力的一种方式,这允许我们创建更加语义化的配置元素,提高代码的可读性和可维护性。本文将深入探讨如何结合Spring来实现自定义XML标签,并利用FactoryBean进行代理...

    SpringSecurity 之自定义用户权限信息的存取

    本文将详细探讨SpringSecurity中关于自定义用户权限信息存取的实现方法,包括如何通过配置文件和数据库来管理用户的认证信息和权限数据。 首先,当我们谈论用户权限信息的存取,实际上是在处理两个方面的问题:用户...

    Struts2、Spring、Freemarker自定义标签

    Spring框架也有自己的标签库,如Spring Taglib,可以简化JSP页面中的Spring Bean引用。而在Freemarker中,可以通过扩展其API创建自定义指令,实现更复杂的逻辑或功能。 总结一下,Struts2、Spring和Freemarker的...

    spring自定义切面实例

    在Spring配置文件中,可以通过`&lt;aop:aspectj-autoproxy/&gt;`标签启用AspectJ的自动代理功能。这意味着Spring容器会自动为标记了@Aspect注解的类创建AOP代理,而无需手动配置。 #### 3. **自定义注解定义切点** 为了...

Global site tag (gtag.js) - Google Analytics