基于注解(Annotation-based)的配置
2009-12-02 16:33
435 查看
Spring 2.0 对必须的属性引入了@Required注解。在 Spring 2.5中已经可以用注解的方式去驱动 Spring 的依赖注射了。更重要的是,
@Autowired注解提供了与第 3.3.5 节 “自动装配(autowire)协作者”一节中描述的同样功能,并且提供了更细致的控制与更好的适应性。Spring 2.5 也支持 JSR-250 中的一些注解,例如
@Resource,
@PostConstruct,以及
@PreDestroy。当然,要使注解可用,您必须使用 Java 5 (Tiger)或更新的版本,以使得可以访问源代码层次的注解。这些注解可以被注册为独立 bean 的定义,但它们也可以被隐式地注册,通过基于 XML 的配置方式,如下例(请注意包含 '
context' 命名空间):
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> </beans>
(隐式注册 post-processors 包括了
AutowiredAnnotationBeanPostProcessor,
CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,也包括了前面提到的
RequiredAnnotationBeanPostProcessor。)
3.11.1. @Autowired
@Autowired注解可以用于“传统的”setter 方法,如下例:
public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
这个注解也可以用于以属性为参数/多个参数的方法
public class MovieRecommender { private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) { this.movieCatalog = movieCatalog; this.customerPreferenceDao = customerPreferenceDao; } // ... }
@Autowired注解甚至可以用于构造器与字段:
public class MovieRecommender { @Autowired private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) { this.customerPreferenceDao = customerPreferenceDao; } // ... }
也可以一种提供来自
ApplicationContext的特殊类型的所有 beans,注解字段或者方法,例如:
public class MovieRecommender { @Autowired private MovieCatalog[] movieCatalogs; // ... }
这同样适用于集合类型:
public class MovieRecommender { private Set<MovieCatalog> movieCatalogs; @Autowired public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) { this.movieCatalogs = movieCatalogs; } // ... }
甚至是 Maps 也可以这样注解,只要这个 Map 的 key 类型为
String。这个 Map 的 values 应该是已知的类型,并且 keys 应该包含符合 bean 的命名:
public class MovieRecommender { private Map<String, MovieCatalog> movieCatalogs; @Autowired public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) { this.movieCatalogs = movieCatalogs; } // ... }
在缺省情况下,当出现0个候选的 beans时自动连接将失败;缺省行为把连接方法,构造器,字段假设为 required 的依赖。这样的行为如下所示:
public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired(required=false) public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
注意
虽然当 一个类只有一个连接构造器时它将被标记为 required, 但是还是可以标记多个构造器的。在这种情况下,每一个构造器都有可能被认为是连接构造器, Spring 将会把依赖关系能够满足的构造器认为是greediest 的构造器。@Autowired也能用于总所周知的“可解决的依赖”:
BeanFactory接口,
ApplicationContext接口,
ResourceLoader接口,
ApplicationEventPublisher接口,还有
MessageSource接口。这些接口(还有它们的扩展,例如
ConfigurableApplicationContext或者
ResourcePatternResolver)将可以自动解决依赖,没有任何特殊必须的其它步骤需要。
public class MovieRecommender { @Autowired private ApplicationContext context; public MovieRecommender() { } // ... }
3.11.2. 基于注解的自动连接微调
因为通过类型的自动连接可能会有多个候选,因此经常需要在选择过程中加以控制。一种方法去完成这个控制就是使用@Qualifier注解。在最简单的情况下,您能够通过命名方式去实现这个自动连接:
public class MovieRecommender { @Autowired @Qualifier("mainCatalog") private MovieCatalog movieCatalog; // ... }
@Qualifier注解也能够被指定为构造器的参数或者方法的参数:
public class MovieRecommender { private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired public void prepare(@Qualifier("mainCatalog") MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) { this.movieCatalog = movieCatalog; this.customerPreferenceDao = customerPreferenceDao; } // ... }
您也可以创建您自定义的限定器注解。您只要在定义一个注解时提供
@Qualifier注解就可以了:
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Genre { String value(); }
然后您就能够将这个自定义的限定器与参数用于自动连接的字段:
public class MovieRecommender { @Autowired @Genre("Action") private MovieCatalog actionCatalog; private MovieCatalog comedyCatalog; @Autowired public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) { this.comedyCatalog = comedyCatalog; } // ... }
下一步就是提供信息给候选的 bean 的定义。您能够添加
<qualifier/>标签作为
<bean/>标签的子元素,然后指定
'type'还有
'value'以匹配您的自定义限定器注解。类型必须匹配注解的全名,或者是一个不危险的、方便一点的名字,您也可以使用“短” 类名。参看下例:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> <bean class="example.SimpleMovieCatalog"> <qualifier type="Genre" value="Action"/> <!-- inject any dependencies required by this bean --> </bean> <bean class="example.SimpleMovieCatalog"> <qualifier type="example.Genre" value="Comedy"/> <!-- inject any dependencies required by this bean --> </bean> <bean id="movieRecommender" class="example.MovieRecommender"/> </beans>
在下一节,题目是第 3.12 节 “对受管组件的Classpath扫描”,您将看到使用XML提供给限定器元数据且基于注解的可选解决方案。特别地,请参看:第 3.12.6 节 “用注解提供限定符元数据”。
在某些情况下,有足够充分的理由去使用不带值的注解。这使得注解可以提供更多解决不同类型依赖的能力。例如,在 Internet 连接不可用时,您可以提供一个离线的搜索目录。首先就要定义一个简单的注解:
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Offline { }
然后添加这个注解给字段作为自动连接:
public class MovieRecommender { @Autowired @Offline private MovieCatalog offlineCatalog; // ... }
现在,这个 bean 的定影只组要一个限定器了:
<bean class="example.SimpleMovieCatalog"> <qualifier type="Offline"/> <!-- inject any dependencies required by this bean --> </bean>
另外,也可以定制自己的限定器注解去使用命名的属性或者简单的
'value'属性。如果自动连接时多个属性值被指定给了一个字段或者参数,那么一个 bean 的定义必须全部匹配这些属性的值。例如,考虑如下的注解定义:
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface MovieQualifier { String genre(); Format format(); }
在这种情况下,
Format是一个枚举:
public enum Format { VHS, DVD, BLURAY }
这些字段将与自定义的限定器进行自动连接,包括了每个属性的值:
'genre'以及
'format'。
public class MovieRecommender { @Autowired @MovieQualifier(format=Format.VHS, genre="Action") private MovieCatalog actionVhsCatalog; @Autowired @MovieQualifier(format=Format.VHS, genre="Comedy") private MovieCatalog comedyVhsCatalog; @Autowired @MovieQualifier(format=Format.DVD, genre="Action") private MovieCatalog actionDvdCatalog; @Autowired @MovieQualifier(format=Format.BLURAY, genre="Comedy") private MovieCatalog comedyBluRayCatalog; // ... }
最终,这个 bean 的定义应该与限定器匹配的值。这个列子将说明bean 的元属性可以用于替代
<qualifier/>的子元素。那样的话,
<qualifier/>以及它的属性将优先考虑,但是如果没有限定器的话(参看如下定义的后两个 bean ),自动连接机制将取消以
<meta/>标签标记的值。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> <bean class="example.SimpleMovieCatalog"> <qualifier type="MovieQualifier"> <attribute name="format" value="VHS"/> <attribute name="genre" value="Action"/> </qualifier> <!-- inject any dependencies required by this bean --> </bean> <bean class="example.SimpleMovieCatalog"> <qualifier type="MovieQualifier"> <attribute name="format" value="VHS"/> <attribute name="genre" value="Comedy"/> </qualifier> <!-- inject any dependencies required by this bean --> </bean> <bean class="example.SimpleMovieCatalog"> <meta key="format" value="DVD"/> <meta key="genre" value="Action"/> <!-- inject any dependencies required by this bean --> </bean> <bean class="example.SimpleMovieCatalog"> <meta key="format" value="BLURAY"/> <meta key="genre" value="Comedy"/> <!-- inject any dependencies required by this bean --> </bean> </beans>
3.11.3. CustomAutowireConfigurer
CustomAutowireConfigurer是一个
BeanFactoryPostProcessor,它可以使得在自动连接过程中做更多的自定义选择。特殊地,它允许您注册您自己的自定义限定器注解类型,甚至是它们没有使用 Spring 的
@Qualifier注解标注它们自己。
<bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer"> <property name="customQualifierTypes"> <set> <value>example.CustomQualifier</value> </set> </property> </bean>
请注意,
AutowireCandidateResolver的实现将依赖于 Java 版本。如果在 Java 5 以下,限定器注解是不被支持的,因此自动连接后选将被
'autowire-candidate'的值或者在
<beans/>中元素
'default-autowire-candidates'可用的模式所决定。如果运行在 Java 5 或者更新的版本上,
@Qualifier注解或者任何自定义并在
CustomAutowireConfigurer上注册过的注解都将正常工作。
忽略 Java 版本,决定“主要”的后选(当多个 beans 都配置为自动连接后选时)都是一样的:在这些后选中只要一个 bean 的
'primary'属性定义为
'true'即可。
3.11.4. @Resource
Spring 也提供了使用 JSR-250 bean 属性支持的注射方式。这是一种在 Java EE 5 与 Java 6 中普遍使用的方式(例如,在 JSF 1.2 中映射 beans 或者 JAX-WS 2.0 端点),对于Spring 托管的对象 Spring 可以以这种方式支持映射。@Resource有一个‘name’属性,缺省时,Spring 将这个值解释为要注射的 bean 的名字。换句话说,如果遵循by-name的语法,如下例:
public class SimpleMovieLister { private MovieFinder movieFinder; @Resource(name="myMovieFinder") public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }
如果没有显式地给出名字,缺省的名字将继承于字段名或者 setter 方法名:如果是字段名,它将简化或者等价于字段名;如果是 setter 方法名,它将等价于 bean 属性名。下面这个例子使用名字 "movieFinder" 注射到它的 setter 方法:
public class SimpleMovieLister { private MovieFinder movieFinder; @Resource public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }
注意
注解提供的名字将被BeanFactory解析为 bean 名。请注意,这些名字也可能通过 JNDI 被解析(需要配置 Spring 的
SimpleJndiBeanFactory)。不过,建议您依靠缺省行为与 Spring 的 JNDI 查找功能。
与
@Autowired类似,
@Resource可以回退为与标准 bean 类型匹配(例如,使用原始类型匹配取代特殊命名 bean)来解决著名的"resolvable dependencies":
BeanFactory接口,
ApplicationContext接口,
ResourceLoader接口,
ApplicationEventPublisher接口以及
MessageSource接口。请注意:这只有适用于未指定命名的
@Resource!
下面的例子有一个
customerPreferenceDao字段,首先要查找一个名叫 “customerPreferenceDao” 的 bean,然后回退为一个原始类型以匹配类型
CustomerPreferenceDao。"context" 字段将基于已知解决的依赖类型
ApplicationContext而被注入。
public class MovieRecommender { @Resource private CustomerPreferenceDao customerPreferenceDao; @Resource private ApplicationContext context; public MovieRecommender() { } // ... }
3.11.5. @PostConstruct
与 @PreDestroy
CommonAnnotationBeanPostProcessor不只是能识别
@Resource注解,而且也能识别 JSR-250 lifecycle注解。在 Spring 2.5 中,这些注解的描述请参看initialization callbacks 与 destruction callbacks节。
CommonAnnotationBeanPostProcessor已经在 Spring 的
ApplicationContext中注册,当一个方法带有这些注解之一时,将被在其生命周期与 Spring 生命周期接口的方法或者显式声明回调方法同一刻上调用。下面的例子里,缓存将预置于初始化与销毁阶段。
public class CachingMovieLister { @PostConstruct public void populateMovieCache() { // populates the movie cache upon initialization... } @PreDestroy public void clearMovieCache() { // clears the movie cache upon destruction... } }
注意
关于组合不同的生命周期机制,请查看第 3.5.1.4 节 “组合生命周期机制”。相关文章推荐
- spring(四)之基于注解(Annotation-based)的配置.md
- spring与hibernate整合配置基于Annotation注解方式管理实务
- spring-基于注解(Annotation)的配置(转)
- Struts2基于注解Annotation的零配置开发(一)
- Struts2基于注解Annotation的零配置开发(二)
- 基于Annotation注解整合SSH框架和基于XML文件配置Bean整合SSH框架
- Struts2基于注解Annotation的零配置开发(三)
- spring注解基于Annotation的依赖注入配置笔记
- Spring 4.0 基于注解(Annotation)的配置和理解
- Spring中基于配置XML与Annotation注解配置AOP
- 基于Annotation注解整合SSH框架和基于XML文件配置Bean整合SSH框架
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
- spring4配置基于注解的ehcache缓存
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
- spring Quartz基于配置文件和注解的实现
- Spring框架总结——第二部分(基于xml配置+注解的方式配置IOC)
- 使用@Controller注解为什么要配置<mvc:annotation-driven />
- 基于注解的配置
- [Spring]基于注解的形式配置Bean
- JavaWeb学习笔记-spring-06-ioc-基于注解配置