上节阐述了spring bean 基于xml的配置及其他的bean概述,本届阐述spring基于annotation的方式配置Bean。在这里要说明的是,基于annotation的配置会优先于xml配置方式,所以,对于同一个bean,后续的xml配置会覆盖前面的annotation的配置。
一般可以通过下面的xml进行注册
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
<context:annotation-config/>配置会隐式向spring容器注入AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor 这四个BeanPostProcessor,这四个BeanPostProcessor的作用让系统能够识别相应的注解
常用注解说明
@Required
常用于Bean中属性的setter上
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
这个注解表示被注解的属性需要配置的期间被填充,可以通过在bean中明确的赋值,或者自动装配。如果没有,容器则会抛出异常。
@Autowired
@Autowired可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。
注意:@Autowired是根据类型(byType)进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier使用;
@Autowired 可以使用构造方法上,也可以在传统的setter方法上
在构造上使用:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
在4.3以后,目标Bean中只有一个构造方法,那么可以省略这个注解,如果有多个构造方法,则至少要有一个构造方法要使用@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 {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
private MovieCatalog movieCatalog;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
由于@Autowired
是基于类(byType)实现自动装配的,如果在容器中有多个类,可能会导致程序出错。这使得我们需要自动装备进行更加进一步的限制:
@Primary
这个注解表示如果自动装备的Bean存在有多个候选者,那么这个候选者将会成为自动装配的Bean
javacode-conf:
@Configuration
public class MovieConfiguration {
@Bean
@Primary
public MovieCatalog firstMovieCatalog() { ... }
@Bean
public MovieCatalog secondMovieCatalog() { ... }
// ...
}
xml-conf:
......
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog" primary="true">
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
......
@Qualifier(“main”)
@Autowired
配合@Qualifier("main")
可以实现根据名字进行自动装备,上述代码会装备上具有<qualifier value="main"/>
的Bean。
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/>
<!-- inject any dependencies required by this bean -->
</bean>
@Qualifier()
也可以作为构造或者方法的参数进行使用
@Autowired
public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
这只是@Qualifier()
的最基本用法,更详细的构造@Qualifier()
接口等可以看官方文档说明。
@Resource
使用@Resource
可以实现Bean自动装配时,通过byName 注入。
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder")
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
如果在@Resource
中没带任何参数,则会使用默认的name,这个name与你定义的类对象名称保持一致
public class SimpleMovieLister {
//在此使用@Resource 则会自动装配name="first" 的bean
private MovieFinder first;
//在此使用@Resource 则会自动装配name="second" 的bean
@Resource
public void setMovieFinder(MovieFinder second) {
this.movieFinder = movieFinder;
}
}
需要说明的是,当没有多个同类型的Bean时,@autowired和@Resource
都是可以直接实现自动装配效果的
@PostConstruct and @PreDestroy
public class CachingMovieLister {
//bean初始化之前
@PostConstruct
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
//bean销毁之前
@PreDestroy
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}
使用类路径扫描和管理组件
在上述的注解使用过程中,Bean的初始化配置仍然在XML中,通过上述的注解只是通过解决类中的依赖关系的配置问题。这一部分通过扫描类路径检测出对应组件的方法,而这些组件又由类构成,这就使得我们可以不通过XML初始化Bean。先介绍几个注解
@Component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
@Repository 用于标注数据访问组件,即DAO组件
@Controller用于标注控制层组件(如struts中的action)
@Service用于标注业务层组件
其实下面的三个注解只是第一个注解的细化而已,通过细化可以实现spring自动的异常转换,并且在配合面向切面变成的工具使用更加方便
检测类和bean注册自动化
spring实现组件的自动检测和注册需要做如下的配置
基于XML的配置:
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
//告诉spring需要扫描的包有哪些
<context:component-scan base-package="org.example"/>
</beans>
基于javacode的配置:
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
...
}
spring扫描的范围是通过类似过滤的方式可以自动配置的
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {
...
}
或者
<beans>
<context:component-scan base-package="org.example">
<context:include-filter type="regex"
expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
这段配置表示忽略@Repository注解而使用.*Stub.*Repository 取代
使用components定义容器中的元数据
spring@Component
也可以像@Configuration
一样通过 @Bean
注解像容器中注入元数据
@Component
public class FactoryMethodComponent {
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
public void doWork() {
// Component method implementation omitted
}
}
基于annotation的配置方式的学习暂且到此为止,里面还有很多细节之处没有详细叙述,用到的时候仍需要参考文档