Spring JSR-250注解
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"/>?
在使用Spring2.5的过程中,如果一个对象需要调用一个初始化的回调方法的话,这个回调方法可以采用@PostConstruct来注解。例如一个假想的例子,一个后台任务需要在启动的时候就开始对一个文件目录进行轮询:
public?class?FilePoller?{??@PostConstruct??public?void?startPolling()?{??????}??
}?
类似地,一个在Spring管理对象上用@PreDestroy注解的方法会在这个对象寄宿的应用程序上下文(application context)关闭的时候被调用。
public?class?FilePoller?{@PreDestroypublic?void?stopPolling()?{
}
}?
在添加了对JSR-250注解的支持以后,现在的Spring2.5结合前面提到的两种生命周期方法的长处。将@PostConstruct和@PreDestroy作为方法层注解加入,足可以实现在受Spring管理的上下文(context)中触发回调。换句话说,不需要另外基于XML的配置。同时,这两个注解是Java语言本身的一部分(甚至被包括在Java SE 版本6中),所以无需引入特定Spring包。这两个注解拥有在其他环境中也能理解的标识语义的优点,随着时间的推移,Java开发人员可能会发现这些注解在第三方开发库中被越来越多的运用到。最后,基于注解生命周期回调的其中一个有趣的结果是,不止一个方法可以带有这两个注解中的任何一个,并且所有注解了的方法会被调用。
激活刚刚描述的关于@Resource 、@PostConstruct和@PreDestroy注解的所有行为,正如上文提到的,需要为Spring的CommonAnnotationBeanPostProcessor提供一个bean定义。但另一个更简练的方法则可能是使用2.5中的新的context命名空间:
<context:annotation-config/>
引入这个单个元素将不单单注册一个CommonAnnotationBeanPostProcessor,也会像下文将叙述的那样激活自动装配(autowire)行为。CommonAnnotationBeanPostProcessor也为@WebServiceRef 和@EJB注解提供支持。这些将在本文系列的第三篇中和Spring2.5为企业集成提供的其他新特性一起讨论。
利用注解来优化细粒度自动装配涵盖Spring对自动装配支持的文档中常常会提到由于自动装配机制的粗粒度而伴随有很多限制性。Spring2.5之前,自动装配可以通过很多不同的方式来配置:构造器,类型setter,名字setter,或者自动侦测(在该方式中Spring选择自动装配一个构造器或者类型setter)。这些不同的选择确实提供了很大程度的灵活性,但它们中没有一个方法能够提供细粒度控制。换句话说,Spring2.5之前还不可能自动装配某个对象setter方法的特定子集,或者通过类型或名字来自动装配它的一些属性。结果,许多Spring用户意识到将自动装配应用到构建原型和测试中的好处,但当提到在产品中维护和支持系统时,大部分人认为,加入冗长的显式配置对于澄清它所担负的职责是非常值得的。
然而,Spring2.5大幅度地改变了布局。如上文所述,自动配置选项现在已经被扩展,支持JSR-250 @Resource注解来激活在每个方法或域基础上被命名资源的自动装配。然而,@Resource注解若单独使用的话有很多限制。因此,Sring2.5引进了一个名为@Autowired的注解进一步提高控制级别。为激活这里所讲的行为需要注册一个单独的bean定义:
<bean?class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
另外如上文提到的,context命名空间提供了一个更简明的方法。它将激活本文所讨论的两个post-processor(AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor)和我们在Spring2.0中引入的基于注解的post-processor:RequiredAnnotationBeanPostProcessor和PersistenceAnnotationBeanPostProcessor。
<context:annotation-config/>
利用@Autowired 注解可以对相应类型注入依赖。域、构造器和方法都可以激活此行为。实际上,aotowired方法并不一定要是setter方法,且可以接受多个参数。下面这个例子是完整的可接受的用法:
@Autowiredpublic?void?setup(DataSource?dataSource,?AnotherObject?o)?{?
?}?
默认地,标有@Autowired注解的依赖被认为是必须的。然而,也可以将required属性值设置为false来声明它们中的任何一个。在下面这个例子中,DefaultStrategy只有在context命名空间中没有SomeStrategy类型的Spring管理对象时才能被使用。
@Autowired(required=false)private?SomeStrategy?strategy?=?new?DefaultStrategy();?
通过类型进行的自动装配明显地在Spring context包含多于一个期望类型的对象的时候造成歧义。默认地,如果一个必须的依赖没不是恰好一个bean与之对应的话,自动装配机制就会失败。同样的,对于任何一个可选属性,如果它拥有一个以上的候选,也都会失败(如果属性可选且没有任何候选可用的话,该属性则会被简单地跳过)。有很多不同的配置选项可以避免这些冲突。
若Context中拥有一个指定类型的一个主关键实例,对这个类型定义的bean定义应该包含‘primary’属性。当Context中含有其他可用实例的时候这个方法就很适用,但那些非主关键实例总是显式配置的。
<bean?id="dataSource"?primary="true"??/>?
在需要更多控制的时候,任何autowired的域、构造参数、或者方法参数可以进一步加注@Qualifier注解。qualifier可以包含一个字符串值,在这种情况下,Spring会试图通过名字来找到对应的对象。
@Autowired@Qualifier("primaryDataSource")private?DataSource?dataSource;?
@Qualifier作为一个独立注解存在的主要原因是它可以被应用在构造器参数或方法参数上,但上文提到的@Autowired注解只能运用在构造器或方法本身。
@Autowiredpublic?void?setup(@Qualifier("primaryDataSource")?DataSource?dataSource,?AnotherObject?o)?{?
?}?
事实上,@Qualifier作为一个单独的注解在定制化方面提供了更多的好处。用户自定义的注解在自动装配过程中也可以起到qualifier的作用,最简单的实现方式是在运用自定义注解的同时将@Qualifier作为它的元注解。
@Target({ElementType.FIELD,?ElementType.PARAMETER,?ElementType.TYPE,?ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Qualifierpublic?@interface?VetSpecialty?
{?
?}?
自定义注解可以选择包含一个值来提供通过名字匹配的功能,但更普遍的用法是将它作为“标记”注解或定义一个对qualifier过程提供一些更多含义的值。例如,下面这个摘录则描绘了一个域,它应该和通过名字匹配得到的结果中合格的对象进行自动装配。
@Autowired@VetSpecialty("dentistry")private?Clinic?dentistryClinic;?
在使用XML配置来达到依赖解析的目标时,'qualifier' 子元素可以被加注到bean定义中。在下文的组件扫描部分,我们将呈现一个可供选择的非XML方法。
<bean?id="dentistryClinic"?class="samples.DentistryClinic"><qualifier?type="example.VetSpecialty"?value="dentistry"/></bean>?
为了避免对@Qualifier注解的任何依赖性,可以在Spring context中提供一个CustomAutowireConfigurer的bean定义并直接注册所有自定义注解类型:
<bean?class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer"><property?name="customQualifierTypes"><set><value>example.VetSpecialty</value></set></property></bean>?
现在,自定义修饰符被显式声明了,就不再需要@Qualifier这个元注解符了。
@Target({ElementType.FIELD,?ElementType.PARAMETER,?ElementType.TYPE,?ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)public?@interface?VetSpecialty?{??}?
其实,在配置AutowiredAnnotationBeanPostProcessor的时候,取代@Autowired注解都是有可能的。
<bean?class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"><property?name="autowiredAnnotationType"?value="example.Injected"/></bean>?
大部分情况下,定义自定义‘标记’注解的能力结合通过名字或其他文法值进行匹配选项,足以完成自动装配过程的细粒度控制。但Spring还支持在qualifier注解上任意数目的任意属性。比如,下面是一个极为细粒度修饰的例子。
@SpecializedClinic(species="dog",?breed="poodle")private?Clinic?poodleClinic;?
自定义修饰符的实现应该定义这些属性:
@Target({ElementType.FIELD,?ElementType.PARAMETER,?ElementType.TYPE,?ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Qualifierpublic?@interface?SpecializedClinic?
{String?species();String?breed();}?
自定义修饰符属性可以匹配那些XML中bean定义的qualifier注解的属性子元素。这些元素通常以键/值对方式提供。
<bean?id="poodleClinic"?class="example.PoodleClinic"><qualifier?type="example.SpecializedClinic"><attribute?key="species"?value="dog"/><attribute?key="breed"?value="poodle"/></qualifier></bean>?
目前为止,关于autowire的描述都只是针对单独的实例,其实也支持集合。在任何需要得到所有context中某种特定类型的Spring管理对象的时候,只需要简单地在一个强类型(strongly-typed)集合上加注@Autowired 注解。
@Autowiredprivate?List<Clinic>?allClinics;?
本章节最后一个值得指出的特性是自动装配的使用替代了Spring的Aware接口。在Spring2.5之前,如果某个对象需要一个Spring context的ResourceLoader的引用,它可以通过实现ResourceLoaderAware的方式使得Spring通过setResourceLoader(ResourceLoader resourceLoader)方法来提供该依赖。借助同样的方法可以得到Spring管理的MessageSource的引用,甚至可以得到ApplicationContext本身。对于Spring2.5用户而言,这个行为现在通过autowiring得到全面支持(需要指出的是包含这些Spring特定依赖的时候应该考虑周到,特别是它们只能用于从业务逻辑清楚地分割出来的基础构架代码中)。
@Autowiredprivate?MessageSource?messageSource;@Autowiredprivate?ResourceLoader?resourceLoader;@Autowiredprivate?ApplicationContext?applicationContext;自动侦测Spring组件
从2.0版本开始,Spring引入了构造型(stereotype)注解的概念以及将@Repository注解作为数据访问代码的标记的方法。在此基础上,Spring2.5又加入了两个新的注解 —— @Service和@Controller 来完成为通常的三层架构(数据访问对象、服务、web控制器)角色委任。Spring2.5也引入了泛型@Component注解,其他构造型可从逻辑上对其进行扩展。通过清晰地指明应用程序的角色,这些构造型方便了Spring AOP和post-processor的使用,这些post-processor给基于这些角色的加了注解的对象提供了附加行为。比如,Spring2.0引入了PersistenceExceptionTranslationPostProcessor对任何带有@Repository 注解的对象自动激活其数据访问异常转换。
这些注解同样可以结合Spring2.5其他一些新性能来使用:自动侦测classpath上的组件。尽管XML已经成为最常见的Spring元数据的格式,但它决不是唯一选择。实际上,Spring容器内的元数据是由纯Java来表示的,当XML被用来定义Spring管理对象时,在实例化过程之前,那些定义会被解析并转化成Java对象。Spring2.5的一个巨大的新功能是支持从源码层注解读取元数据。因而,上文描述的自动装配机制使用注解的元数据来注入依赖,但它仍然需要注册至少一个bean定义以便提供每个Spring管理对象的实现类。组件扫描功能则使得这个XML中最起码的bean定义都不再存在需求性。
正如上面所示,Spring注解驱动的自动装配可以在不牺牲细粒度控制的前提下极大程度地减少XML的使用。组件侦测机制将这个优点更发扬光大。全面替代XML中的配置不再必要,组件扫描反而可以处理XML元数据来简化整体配置。结合XML和注解驱动技术可以得到一个平衡优化的方法,这在2.5版本的PetClinic范例中有详细阐述。在该范例中,基础构架组件(数据源、事务管理等)结合上文提到的外化属性在XML中定义。数据访问层对象也有部分在XML中定义,它们的配置也都利用了@Autowired注解来简化依赖注入。最后,web层控制器完全不在XML中显式定义,相反,下面提供的这段配置被用来触发所有web控制器的自动侦测:
<context:component-scan?base-package="org.springframework.samples.petclinic.web"/>
需要注意到的是这段示例中使用到了base-package属性。组件扫描的默认匹配规则会递归侦测该包(多个包可以以逗号分隔的list方式提供)内的所有类的所有Spring构造型注解。正因为如此,PetClinic应用程序范例中的各类控制器的实现都采用了@Controller注解(Spring的内置构造型之一)。请看下面这个例子:
@Controllerpublic?class?ClinicController?{private?final?Clinic?clinic;@Autowiredpublic?ClinicController(Clinic?clinic)?
{this.clinic?=?clinic;}
?
自动侦测组件在Spring容器中注册,就像它们在XML中被定义一样。如上所示,那些对象可以轮流利用注解驱动的自动装配。
组件扫描的匹配规则可以通过过滤器(filter)来自定义,以根据类型、AspectJ表达式、或针对命名模式的正则表达式来决定包含或不包含哪些组件。默认的构造型也可以被禁用。比如这里有一个配置的例子,这个配置会忽略默认的构造型,但会自动侦测名字以Stub打头或者包含@Mock注解的所有类:
<context:component-scan?base-package="example"?use-default-filters="false"><context:include-filter?type="aspectj"?expression="example..Stub*"/><context:include-filter?type="annotation"?expression="example.Mock"/></context:component-scan>?
类型匹配的限制性也可以用排他的过滤器控制。例如,除了@Repository注解外其他都依赖于默认过滤器,那么就需要加入一个排他过滤器(exclude-filter)。
<context:component-scan?base-package="example"><context:exclude-filter?type="annotation"?expression="org.springframework.stereotype.Repository"/></context:component-scan>?
很明显,有很多方法可以扩展组件扫描来注册自定义的类型。构造型注解是最简单的选择,所以构造型概念本身也是可扩展的。像先前提到的,@Component是泛型模型,@Repository、@Service,和@Controller注解都从该构造型逻辑扩展而得。正因为如此,@Component可被用来作为元注解(也就是说,在另外的注解上声明的注解),所有具有@Component元注解的自定义注解都会被默认扫描匹配规则自动侦测到。一个例子就有希望让你领会到其实它根本没有听起来那么难。
让我们回想一下在讲@PostConstruct和@PreDestroy生命周期注解的时候的假想的后台任务。也许一个应用程序有很多很多这样的后台任务,这些任务实例需要XML bean定义以便在Spring context里注册并使它们自己的生命周期方法在正确时候被调用。利用组件扫描就不再需要这些显式的XML bean定义。如果这些后台任务都实现一个相同的接口或者都沿用同样的命名惯例,那么可以用include-filters。然而,更简单的方法是为这些任务对象创建一个注解并提供@Component元注解。
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic?@interface?BackgroundTask?
{String?value()?default?"";}?
然后在所有后台任务的类定义中提供自定义构造型注解。
@BackgroundTaskpublic?class?FilePoller?{@PostConstructpublic?void?startPolling()?
{
}@PreDestroypublic?void?stopPolling()?
{
}
}?
泛型@Component注解可以像例子中提供的那样简单使用,自定义注解技术则提供了一个使用更具涵义的、领域特定的名字的机会。这些领域特定注解提供更深入的机会,比如使用AspectJ切点表达式来识别所有后台任务,以便增加advice来监控这些任务的活动性。
默认的,组件被侦测到的时候,Spring会自动生成一个没有修饰符的类名作为bean名字。上一个例子中,生成的bean名字会是filePoller。但是,任何加注了Spring构造型注解(@Component、@Repository、@Service或 @Controller)或是加注了其他的以@Component作为元注解的注解(比如上面例子中的@BackgroundTask )的类,构造型注解的value属性可以被显式指定,实例将该值作为它的bean名字注册到context中。接下来的例子里,实例名应该是petClinic而不是默认生成的名字simpleJdbcClinic。
@Service("petClinic")public?class?SimpleJdbcClinic?{
}?
同样的,在下面修正版的FilePoller例子里,生成的bean名字应该是poller而不是filePoller。
border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding