基于注释的容器配置
通过基于注解的配置提供了XML设置的替代方法,该配置依赖于元数据(metadata)来连接组件。
注解
<context:annotation-config/>
只会在同一应用上下文寻找bean定义,所以,在WebApplicationContext中使用<context:annotation-config/>,它只会检查在Controller层标记@Autowired声明的bean而不会到你的Service层中去找(因此Controller和Service都要分别定义<context:annotation-config/>)
注意:<context:annotation-config/>和<context:component-scan>的区别
- @Required
被标注的bean必须的相关值必须被填充(注入), 如果没有被填充(注入),则容器会报错。这允许急切和明确的失败,以后避免NullPointerExceptions等
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
注意
如果你用java config形式配置bean的话@Required是不起作用的
(https://stackoverflow.com/questions/16769360/how-does-required-annotation-work-with-javaconfig)
So, to summarize: @Required
doesn't work with @Configuration
classes by default. If you need to make sure that all your properties are set, you can just as well do it yourself when you create the bean in the @Bean
methods (By calling some init
method that performs such validations, or just supplying the required properties yourself). And if you really need to make the @Required
annotation work, you'd need to use your own implementation of the RequiredAnnotationBeanPostProcessor
, register it as a bean in the spring context and give up the benefits of context:annotation-config
.
- @Autowired
可以注解在setter方法上,构造器上,具有任意名称和/或多个参数的方法,字段上(fields),数组类型的字段或方法,集合类型的字段或方法上
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
注意
Map类型需要key为String类型才能被注入,key值会对应bean名称。容器会将符合类型的bean都注入到map中,其中key值就是对应的bean名称。
- @Primary
@Autowired是根据类型自动装配的(@Resource(这个注解属于J2EE的),默认安装名称进行装配),按照类型的自动装配可能会导致多个候选,因此通常要对选择过程由更多的控制,其中一个方法时使用Spring的@Primary注解。当有多个附后要求的候选bean时,标有primary的Bean会被注入
public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
@Configuration
public class MovieConfiguration {
@Bean
@Primary
public MovieCatalog firstMovieCatalog() { ... }
@Bean
public MovieCatalog secondMovieCatalog() { ... }
// ...
}
- @Qualifier
按照类型的自动装配可能会导致多个候选,因此通常要对选择过程由更多的控制,Spring的@Qualifier注释,可以将限定符值与特定参数关联,缩小类型匹配集
public class MovieRecommender {
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
// ...
}
@Qualifier也可以标注在单独的构造器参数或方法参数上。
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
<?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/>
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier value="action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
限定符也适用于类型化的集合,如上所述,例如 Set<MovieCatalog>。在这种情况下,根据声明的限定符的所有匹配的bean将作为集合进行注入。这意味着限定词不一定是唯一的; 它们只是构成过滤标准。例如,您可以MovieCatalog使用相同的限定符值“action” 定义多个bean,所有这些bean都将注入到Set<MovieCatalog>注释中@Qualifier("action")。
注意
如果你打算按名称注入Bean,不要用@Autowired,请使用@Resource(JSR-250定义的)
- @Resource
@Resource默认按名称注入,如果没有明确指定名称,则默认名称来自字段名称或setter方法。在一个字段的情况下,它需要字段名称; 在setter方法的情况下,它将使用bean属性名称。如果没有明确指定名称,默认名称也找不到对应的bean就和@Autowired类似.
public class MovieRecommender {
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
以上几个注解,我都做了相应的练习去验证https://github.com/wingofthestar/SpringLearn
位于site.yourdiary.anno目录下
@Controller、@Service、@Repository、@Component
@Component是标志着任何被Spring管理的组件(Bean)
@Repository, @Service, @Controller是对于@Component更具体的特定用例的组件。
你可以用 @Component注解组件类,但如果用@Repository,@Service或者@Controller ,你的类有可能能更好地被工具处理,或与切面进行关联。
- 元注解
Spring 提供的许多注解可以在你自己的代码中用作元注解。元注解是可以应用于另一个注解的注解。例如,@Service注解就是以@Component为元注解的
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // Spring will see this and treat @Service in the same way as @Component
public @interface Service {
// ....
}
元注解可以组合成组合注解,就比如在SpringMVC中@RestController就是由@Controller和@ResponseBody组合而成的。
- 自动检测类和注册bean定义
Spring可以自动检测注解有(stereotyped)的类,并在ApplicationContext中注册相应的BeanDeinitions.
例如:
@Service
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
@Repository
public class JpaMovieFinder implements MovieFinder {
// implementation elided for clarity
}
为了自动检测这些类,并且注册相应的Bean,你需要添加在@Configuration类上标注@ComponentScan,并且标记basePackages属性为这两个类的父包。(也可以用逗号、分号、空格分隔的列出每个class的父包)。
java config写法
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
...
}
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:component-scan base-package="org.example"/>
</beans>
注意
<context:component-scan>启用(包含)了<context:annotation-config>的功能,所以使用了<context:component-scan>就不需要再添加<context:component-scan>
Furthermore, the AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor are both included implicitly when you use the component-scan element. That means that the two components are autodetected and wired together - all without any bean configuration metadata provided in XML.
AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也同时被自动检测到并注册
使用过滤器自定义扫描(路径)
下面的例子展示了configuration忽略了所有@Repository注解,并用"stub" respositories
@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>
使用JSR-330标准注解
从Spring 3.0开始,提供对JSR-330标准注释(依赖注入)的支持。这些注释以与Spring注释相同的方式进行扫描。你只需要在你的classpath中有相关的jar。
可以在maven的pom.xml中添加
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
- 使用@Inject和@Named
如果您想要使用限定名称作为应注入的依赖项,则应使用@Named注释
import javax.inject.Inject;
import javax.inject.Named;
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Inject
public void setMovieFinder(@Named("main") MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
- @Named和@ManagedBean:@Component注释的标准等价物
Instead of @Component, @javax.inject.Named or javax.annotation.ManagedBean may be used as follows:
import javax.inject.Inject;
import javax.inject.Named;
@Named("movieListener") // @ManagedBean("movieListener") could be used as well
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Inject
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
当使用@Named或@ManagedBean时可以使用与使用Spring注解完全相同的组件扫描
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
...
}
- JSR-330标注注解的限制