`
gaoyuntao2005
  • 浏览: 311225 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

spring 扩展

阅读更多

Spring的可扩展点做得比hibernate好多了,参考文档上就可以找到扩展spring配置文件的方法。利用在类路径的META-INF目录下加入spring.handlers和spring.schemas两个文件来作为扩展的入口。
   
我的思路是这样的,通过在一个spring总的配置文件中,比如applicationContext.xml中,加入一段我自定义的xml标签,在这个标签上定义我需要注册的spring的service bean在什么类路径下。然后spring在启动时,读取到该标签上定义的类路径,寻找该类路径下被我用annotation标注过的类,将该类注册到spring容器中。

第一步,定义标识service bean的annotation:
该annotation其实只需要一个属性,该service bean注册到spring中的id,所以我建立了如下的名字叫Bean的annotation类:

Java代码 复制代码
  1. @Target({ElementType.TYPE})   
  2. @Retention(RetentionPolicy.RUNTIME)   
  3. @Documented  
  4. public @interface Bean {   
  5.     //获取bean id   
  6.     String id();   
  7. }  
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
	//获取bean id
	String id();
}


该annotation只能定义在类或者接口上,只有一个属性id,必填。用它标识后的service bean如下:

Java代码 复制代码
  1. @Bean(id="sample.lesson.student")   
  2. public class StudentServiceBean implements IStudent {  
@Bean(id="sample.lesson.student")
public class StudentServiceBean implements IStudent {



第二步,扩展spring xml配置,定义service bean所在的目录:
前面已经说过,我们需要在applicationContext.xml这个总配置文件中定义service bean所在的目录。于是我在applicationContext.xml加入如下的tag:

Xml代码 复制代码
  1. <sa:annotation-autoload >  
  2.     <sa:package>sample/service/lesson </sa:package>  
  3. <sa:package>sample/service/student</sa:package>  
  4. </sa:annotation-autoload>  
<sa:annotation-autoload >
	<sa:package>sample/service/lesson </sa:package>
<sa:package>sample/service/student</sa:package>
</sa:annotation-autoload>


加完后,eclipse的schemas校验功能已经告诉我们,出错误了。因为spring中并没有sa:annotation-autolaod和sa:package这样的标签,所以我们需要扩展spring校验用的schemas。扩展的方法就是在applicationContext文件中的beans根节点加入对schemas定义的代码:

Xml代码 复制代码
  1. <beans xmlns="http://www.springframework.org/schema/beans"  
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xmlns:aop="http://www.springframework.org/schema/aop"  
  4.     xmlns:tx="http://www.springframework.org/schema/tx"  
  5.     xmlns:sa="http://leeon.iteye.com/context"  
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
  7.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd   
  8.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd   
  9.            http://leeon.iteye.com/context http://leeon.iteye.com/context.xsd">  
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:sa="http://leeon.iteye.com/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
           http://leeon.iteye.com/context http://leeon.iteye.com/context.xsd">


这段代码中,xmns:sa=http://leeon.iteye.com/context定义了xml tag的前缀是sa,而xsi:chemaLocation中定义的 http://leeon.iteye.com/context http://leeon.iteye.com/context.xsd指向了schemas xsd文件的位置。当然,不能让系统真的访问互联网去下载这个xsd了,可以通过在META-INF中创建的spring.handlers和spring.schemas文件类来定义schemas在本地类路径中的位置以及相关的handle这个schemas定义的xml tag的解析类,Spring加载时会通过这两个文件找到xsd和handler解析类的本地版本。

第三步,建立spring.handlers和spring.schemas以及相关的xsd和handler
于是在/META-INF中创建spring.schemas,内容如下:http\://leeon.iteye.com/context.xsd=leeon/extend/spring/context.xsd
这句话说明了真正校验我们自定义tag的xsd在leeon/extend/spring的类路径下
说明了位置后,我们就可以创建context.xsd,该xsd就是普通的校验xml用的xsd,不多做描述。可以参考以下代码:

Xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
  2. <xsd:schema xmlns="http://leeon.iteye.com/context" xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
  3.     targetNamespace="http://leeon.iteye.com/context" elementFormDefault="qualified" attributeFormDefault="unqualified">  
  4.     <xsd:annotation>  
  5.         <xsd:documentation>  
  6.             <![CDATA[  
  7.         XML Schema for the Spring-Annotation module, it enables the use of annotations to configure your Spring-Framework application  
  8.         ]]>  
  9.         </xsd:documentation>  
  10.     </xsd:annotation>  
  11.     <xsd:element name="annotation-autoload">  
  12.         <xsd:annotation>  
  13.             <xsd:documentation>  
  14.                 <![CDATA[Enables the scanning of anotated classes in the classpath, the scanDirs attribute tells to scan all open directories in the classpath, and the jarMarkerFile enables you to tell the scanner to loog for a file named different from to.properties in the jar files.]]>  
  15.             </xsd:documentation>  
  16.         </xsd:annotation>  
  17.         <xsd:complexType>  
  18.             <xsd:sequence>  
  19.                 <xsd:element name="package" type="xsd:string" minOccurs="0" maxOccurs="unbounded">  
  20.                     <xsd:annotation>  
  21.                         <xsd:documentation>  
  22.                             <![CDATA[defines that the scanner will only include files that match with this.]]>  
  23.                         </xsd:documentation>  
  24.                     </xsd:annotation>  
  25.                 </xsd:element>  
  26.             </xsd:sequence>  
  27.             <xsd:attribute name="pattern" type="xsd:string" default=".*\.class" use="optional" />  
  28.         </xsd:complexType>  
  29.     </xsd:element>  
  30. </xsd:schema>  
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://leeon.iteye.com/context" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://leeon.iteye.com/context" elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xsd:annotation>
		<xsd:documentation>
			<![CDATA[
		XML Schema for the Spring-Annotation module, it enables the use of annotations to configure your Spring-Framework application
		]]>
		</xsd:documentation>
	</xsd:annotation>
	<xsd:element name="annotation-autoload">
		<xsd:annotation>
			<xsd:documentation>
				<![CDATA[Enables the scanning of anotated classes in the classpath, the scanDirs attribute tells to scan all open directories in the classpath, and the jarMarkerFile enables you to tell the scanner to loog for a file named different from to.properties in the jar files.]]>
			</xsd:documentation>
		</xsd:annotation>
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="package" type="xsd:string" minOccurs="0" maxOccurs="unbounded">
					<xsd:annotation>
						<xsd:documentation>
							<![CDATA[defines that the scanner will only include files that match with this.]]>
						</xsd:documentation>
					</xsd:annotation>
				</xsd:element>
			</xsd:sequence>
			<xsd:attribute name="pattern" type="xsd:string" default=".*\.class" use="optional" />
		</xsd:complexType>
	</xsd:element>
</xsd:schema>



接下来创建spring.handlers,内容如下:http\://leeon.iteye.com/context=leeon.extend.spring.EnableAnnotationHandler,这句话说明了Handler处理类所在的类路径,是真正处理我们在xml定义的tag的handler类。

创建时必须继承org.springframework.beans.factory.xml.NamespaceHandlerSupport类。该类是一个抽象类,必须实现的方式就是init,在这个方法中,告诉spring容器,处理哪些tag,需要哪些BeanDefinitionParser,代码如下:

Java代码 复制代码
  1. public class EnableAnnotationHandler extends NamespaceHandlerSupport {   
  2.     public void init() {   
  3.         registerBeanDefinitionParser("annotation-autoload",    
  4. new AnnotationAutoloadBeanDefinitionParser());   
  5.     }   
  6. }  
public class EnableAnnotationHandler extends NamespaceHandlerSupport {
    public void init() {
        registerBeanDefinitionParser("annotation-autoload", 
new AnnotationAutoloadBeanDefinitionParser());
    }
}


这里就是告诉spring容器,初始化处理annotation-autoload这个的xml element时,使用AnnotationAutoloadBeanDefinitionParser,该Parser是一个实现了BeanDefinitionParser接口的类。

第四步,实现自定义的BeanDefinitionParser
BeanDefinitionParser接口中,必须实现的方法是parse方法。顾名思义,我们要在这个方法中解析自定义的xml element,然后拿到在xml定义的service bean所在的类路径,再将该路径下被@Bean注册过的类,注册到spring的容器中。

Java代码 复制代码
  1. public BeanDefinition parse(Element element, ParserContext parserContext) {   
  2. }  
public BeanDefinition parse(Element element, ParserContext parserContext) {
}


Parse的两个参数:
1. Element表示需要被我们解析的自定义的xml element对应的对象,这里对应的就是<sa:annotation-autoload>节点及其子节点。通过该对象我们可以获取我们配置的类路径,并搜索类路径,找到需要注册到spring容器中的类以及注册后的id。
2. ParserContext,BeanDefinitionParser的相关上下文环境,我们可以从这个参数中去到spring的类注册器,并进行spring bean的注册:

Java代码 复制代码
  1. //从parserContext中获取bean注册器   
  2. BeanDefinitionRegistry bdr = parserContext.getRegistry();   
  3.   
  4. //从创建一个spring bean的定义,并设定一下初始化值   
  5. //setBeanClass就是设定符合条件的service bean对应的class   
  6. final RootBeanDefinition rbd = new RootBeanDefinition();   
  7. rbd.setAbstract(false);   
  8. rbd.setBeanClass(c);   
  9. rbd.setSingleton(false);   
  10. rbd.setLazyInit(false);                
  11.   
  12. //将spring bean的定义,通过id,注册到spring容器中   
  13. //这里的id就是从annotation中去到的service bean对应的spring bean id   
  14. bdr.registerBeanDefinition(id, rbd);  
//从parserContext中获取bean注册器
BeanDefinitionRegistry bdr = parserContext.getRegistry();

//从创建一个spring bean的定义,并设定一下初始化值
//setBeanClass就是设定符合条件的service bean对应的class
final RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setAbstract(false);
rbd.setBeanClass(c);
rbd.setSingleton(false);
rbd.setLazyInit(false);				

//将spring bean的定义,通过id,注册到spring容器中
//这里的id就是从annotation中去到的service bean对应的spring bean id
bdr.registerBeanDefinition(id, rbd);



另外,该方法虽然需要返回值,但也是可以返回null的。定义好这个AnnotationAutoloadBeanDefinitionParser后,将spring bean注册的xml代码移植到annotation上就大功告成。当spring启动解析到<sa:annotation-autoload>标签时,就会将处理的过程交给AnnotationAutoloadBeanDefinitionParser,有Parser里的parse方法来解析到service bean所在路径,搜索,获取id和class,最后加载完成。

首先是定义好我们要用的annotation,定之前,我们先确定了一个开发的基本标准,也就是一个action类需要包括针对一个业务对象操作的多个action方法,也就是说比如StudentAction,将会包括listStudent, removeStudent, editStudent, loadStudent, addStudent等多个action方法,我想这个粒度是比较合适,action类不会太多,也不会将太多的action方法堆积到一个action类中。

我定义了9个annotation,包括:

Package:定义在Action类上,包括namespace属性,parent属性。系统启动时搜索指定类路径下所有被Package标志过的类,作为Action类,并读取相关的namespace和parent属性。当然这样做也有一个缺点,package和类的层次绑定死了,如果想要两个不同的action方法分别在两个不同的类中,但需要在同一个package下时,就显得不够灵活,但我想这样的情况应该比较少,所以没有多考虑。

Java代码 复制代码
  1. @Target({ElementType.TYPE})   
  2. @Retention(RetentionPolicy.RUNTIME)   
  3. @Inherited  
  4. @Documented  
  5. public @interface Package {   
  6.        
  7.     //url名字空间   
  8.     String namespace();   
  9.        
  10.     //父package   
  11.     String parent() default "default";   
  12. }  
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Package {
	
	//url名字空间
	String namespace();
	
	//父package
	String parent() default "default";
}




Action:定义在Action类的相关Action方法上,有name属性和param数组属性。这里定义的name和所在类的Package中定义的namespace组成call该action的url。
Java代码 复制代码
  1. @Target({ElementType.METHOD})   
  2. @Retention(RetentionPolicy.RUNTIME)   
  3. @Documented  
  4. public @interface Action {   
  5.        
  6.     //action name   
  7.     String name();   
  8.        
  9.     //参数   
  10.     Param[] param() default {};   
  11. }  
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
	
	//action name
	String name();
	
	//参数
	Param[] param() default {};
}




ActionResult和ActionResults:用来定义该Action的返回结果,作用在方法上。ActionResults用在定义一个Action有多个ActionResult的时候,ActionResult包括name属性,type属性,value属性(即返回的jsp路径),param属性数组。
Java代码 复制代码
  1. @Target({ElementType.METHOD})   
  2. @Retention(RetentionPolicy.RUNTIME)   
  3. @Documented  
  4. public @interface ActionResult {   
  5.     //result name   
  6.     String name() default Action.SUCCESS;   
  7.     //类型   
  8.     Class type() default NullResult.class;   
  9.     //值,jsp路径   
  10.     String value();   
  11.     //参数   
  12.     Param[] param() default {};   
  13. }   
  14.   
  15.   
  16. @Target({ElementType.METHOD})   
  17. @Retention(RetentionPolicy.RUNTIME)   
  18. @Documented  
  19. public @interface ActionResults {   
  20.     ActionResult[] value();   
  21. }  
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActionResult {
	//result name
	String name() default Action.SUCCESS;
    //类型
	Class type() default NullResult.class;
    //值,jsp路径
	String value();
	//参数
	Param[] param() default {};
}


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActionResults {
	ActionResult[] value();
}



ActionInterceptor和ActionInterceptors:用来定义该Action的拦截器,作用在方法上。ActionInterceptors用在定义一个Action有多个ActionInterceptor的时候,ActionInterceptor包括value属性(该action引用的拦截器的名字),param属性数组。
Java代码 复制代码
  1. @Target({ElementType.METHOD})   
  2. @Retention(RetentionPolicy.RUNTIME)   
  3. @Documented  
  4. public @interface ActionInterceptor {   
  5.     //ref's interceptor name   
  6.     String value();   
  7.     Param[] param() default {};   
  8. }   
  9.   
  10. @Target({ElementType.METHOD})   
  11. @Retention(RetentionPolicy.RUNTIME)   
  12. @Documented  
  13. public @interface ActionInterceptors {   
  14.     ActionInterceptor[] value();   
  15. }  
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActionInterceptor {
	//ref's interceptor name
	String value();
	Param[] param() default {};
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActionInterceptors {
	ActionInterceptor[] value();
}


ActionExceptionMapping和ActionExceptionMappings:用来定义该Actiond的Exception mapping,作用在方法上。ActionExceptionMappings用在定义一个Action有多个ActionExceptionMapping的时候,ActionExceptionMapping包括expceptionClass属性,result属性。
Java代码 复制代码
  1. @Target({ElementType.METHOD})   
  2. @Retention(RetentionPolicy.RUNTIME)   
  3. @Documented  
  4. public @interface ActionExceptionMapping {   
  5.     //class   
  6.     Class exceptionClass();   
  7.        
  8.     //result mapping   
  9.     String result();   
  10.        
  11.     //参数   
  12.     Param[] param() default {};   
  13. }   
  14.   
  15. @Target({ElementType.METHOD})   
  16. @Retention(RetentionPolicy.RUNTIME)   
  17. @Documented  
  18. public @interface ActionExceptionMappings {   
  19.     ActionExceptionMapping[] value();   
  20. }  
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActionExceptionMapping {
	//class
	Class exceptionClass();
	
	//result mapping
	String result();
	
	//参数
	Param[] param() default {};
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActionExceptionMappings {
	ActionExceptionMapping[] value();
}



Param:用来定义以上annotation配置中的参数配置。
Java代码 复制代码
  1. @Target({ElementType.METHOD})   
  2. @Retention(RetentionPolicy.RUNTIME)   
  3. @Documented  
  4. public @interface Param {   
  5.     //参数名称   
  6.     String name();   
  7.     //参数内容   
  8.     String value();   
  9. }  
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Param {
	//参数名称
	String name();
	//参数内容
	String value();
}


以上annotation对象的属性以及配置都是和在xml配置文件中的相关元素的属性以及配置有对应关系的,参考xml配置方式会很快明白以上annotation每个属性的意义。
分享到:
评论

相关推荐

    spring扩展点测试示例代码

    这个压缩包提供的"spring扩展点测试示例代码"是一个实例,帮助我们理解如何在实践中利用Spring的扩展点进行自定义功能的实现。 首先,Spring的核心设计理念之一就是“依赖注入”(Dependency Injection,DI),它...

    基于Java的guerlab-spring设计源码,全面整合Spring扩展工具集

    该项目为基于Java的guerlab-spring扩展工具集设计源码,总计包含82个文件,涵盖59个Java源文件、7个XML配置文件、4个工厂文件、3个属性文件、2个JSON文件、2个SearchParamsUtilInstance配置、1个Git忽略文件、1个...

    spring扩展原理1

    本文主要探讨Spring扩展原理,特别是`BeanFactoryPostProcessor`、`BeanDefinitionRegistryPostProcessor`以及`ApplicationListener`这三种核心扩展点。 首先,`BeanFactoryPostProcessor`是Spring IOC容器中的一种...

    史上最全spring以及扩展功能jar

    本资源包含的"史上最全spring以及扩展功能jar"显然是一个集合了Spring框架及其众多扩展功能的库,旨在提供一站式解决方案,避免开发者在项目中逐一引入所需jar包。 首先,Spring框架的核心组件包括: 1. **Spring ...

    Spring3.0.5扩展支持AOP获取HttpServletResponse

    在Spring 3.0.5版本中,Spring扩展了对AOP的支持,特别是在处理HTTP响应时,可以通过AOP来获取`HttpServletResponse`对象。`HttpServletResponse`是Servlet API中的核心接口,它用于封装服务器向客户端发送的响应...

    SPRING扩展包V1.01

    在上一版本的基础上修正了一些问题.重要的是加入了部分类的JAVADOC. &lt;br&gt;上一版本同志们反映要的分太多.这次打5折:) 以前下过10分那个版本的同志们可以邮件联系我,我可以直接发给新的版本. &lt;br&gt;下一版本打算...

    spring-validation:使用Spring AOP的参数验证Spring扩展

    基于Spring AOP的参数验证框架,在日常的开发过程中,经常会遇到参数校验的问题,使用这个扩展可以把参数校验的逻辑从业务代码中解藕出来,成为单独的模块,使业务代码看起来更清爽。 环境要求 spring-aop 3.2.6....

    akka-spring:测试SPRING扩展提供商

    本篇文章将深入探讨"akka-spring"项目,它作为一个测试SPRING扩展提供商的角色,如何帮助我们整合这两者。 Akka是用Scala编写的,但在Java环境中同样可以很好地工作。它提供了一种基于Actor模型的并发处理机制,每...

    SPRING 扩展包

    在SPRING框架上进行了自己的扩展,欢迎试用.

    spring schema

    在压缩包中的“spring扩展schema.docx”文件,可能是对Spring Schema的详细扩展说明,包括自定义扩展点、自定义标签以及如何在Spring中使用这些扩展来创建自己的解决方案。例如,开发者可能会定义自己的命名空间来...

    Spring常用注解和扩展点

    Spring常用注解和扩展点,Spring常用注解和扩展点,Spring常用注解和扩展点,Spring常用注解和扩展点,Spring常用注解和扩展点,Spring常用注解和扩展点,Spring常用注解和扩展点,Spring常用注解和扩展点

    4.Spring应用扩展.pptx

    《Spring应用扩展》 在Spring框架中,应用扩展是一个重要的概念,它涉及到Spring的灵活性和可配置性。扩展Spring的应用通常包括对配置的拓展、Bean的作用域管理以及依赖注入的实现方式。以下将详细讲解这些知识点。...

    扩展自定义Spring标签思维导图

    实现spring自定义扩展标签的实现步骤

    spring ext 日志管理和导出excel

    在“spring ext 日志管理和导出excel”这个主题中,我们将深入探讨如何利用Spring扩展功能来实现日志管理以及Excel数据导出。 首先,日志管理是任何应用程序的基础部分,它帮助开发者跟踪系统行为、调试问题并记录...

    Spring技术内幕:深入解析Spring架构与设计原理(第2版)

    #### 四、Spring扩展性 1. **插件系统**:Spring框架本身是高度可扩展的,开发者可以通过自定义实现来扩展其功能。 2. **事件驱动**:Spring通过事件机制支持异步处理,提高系统的响应速度和吞吐量。 3. **配置方式...

    Spring容器扩展机制的实现原理

    Spring容器扩展机制的实现原理 Spring框架的核心组件之一是IoC容器,它负责管理容器中所有bean的生命周期。在bean生命周期的不同阶段,Spring提供了不同的扩展点来改变bean的命运。这些扩展点使得开发者可以在容器...

    对spring做java注解扩展

    本文将深入探讨如何在Spring框架中利用Java注解进行扩展,以提升代码的可读性和可维护性。 首先,我们需要了解Java注解(Annotation)。注解是Java语言的一种元数据,它提供了在编译时或运行时对代码进行信息附加的...

    Spring Mybatis Ext整合

    1. 添加依赖:在项目中引入Spring和Mybatis的相关库,包括Spring的core、context、jdbc、orm和Mybatis的核心库以及Mybatis-Spring扩展库。 2. 配置数据源:在Spring配置文件中配置数据源,这通常使用Apache的Dbcp或...

    MyBatis+Spring3整合

    为了解决这个问题,MyBatis 开发团队专门开发了一个扩展包,使得 MyBatis 能够无缝集成到 Spring3 容器中。 这个扩展包,即 `mybatis-spring-1.0.0-RC2.jar`,提供了关键的桥接组件,使得 MyBatis SQL 映射器和数据...

    扩展Spring schema样例代码 maven

    在IT行业中,Spring框架是Java开发中的一个核心组件,它为构建可维护、可扩展的Web应用程序提供了强大的支持。Spring的灵活性和模块化设计使得开发者能够通过XML配置或注解来管理应用程序的组件。本示例代码“扩展...

Global site tag (gtag.js) - Google Analytics