spring–bean的定义及作用域的注解实现
1.Classpath扫描和组件管理
3.0以后,通过java的注解而不是xml来定义bean,如:
@configuration @Bean @Import @DependsOn
- @Component是一个通用注解,可用于任何bean
- @Respority通常注解DAO类,既持久层
- @Service通常用于注解Service类,既服务层
- @Controller通常用于Controller类,既控制层(mvc)
2.元注解
1.许多Spring提供的注解可以作为自己的代码,即”元数据注解”,元注解是一个简单的注解,可以应用到另一个注解
2.除了value(),元注解还可以有其它属性,允许订制
四个元注解分别是:@Target,@Retention,@Documented,@Inherited ,是专门用来定义注解的注解,其作用分别如下:
@Target 表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:
ElemenetType | 说明 |
---|---|
ElemenetType.CONSTRUCTOR | 构造器声明 |
ElemenetType.FIELD | 域声明(包括 enum 实例) |
ElemenetType.LOCAL_VARIABLE | 局部变量声明 |
ElemenetType.METHOD | 方法声明 |
ElemenetType.PACKAGE | 包声明 |
ElemenetType.PARAMETER | 参数声明 |
ElemenetType.TYPE | 类,接口(包括注解类型)或enum声明 |
@Retention 表示在什么级别保存该注解信息。
可选的参数值在枚举类型 RetentionPolicy 中,包括:
RetentionPolicy | 说明 |
---|---|
RetentionPolicy.SOURCE | 注解将被编译器丢弃 |
RetentionPolicy.CLASS | 注解在class文件中可用,但会被VM丢弃 |
RetentionPolicy.RUNTIME VM | 将在运行期也保留注释,因此可以通过反射机制读取注解的信息。 |
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。
在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
@Inherited 允许子类继承父类中的注解。
3.类的自动检测及bean注册
spring可以自动检测类并注册bean到ApplicationContext中
类加@Service@Controller等注解
<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>可以实现基于类的注解,
而<context:annotation-config>只能在完成了bean的注册配置之后实现对成员变量和方法的注解,
前者包含后者,一般配置了前者之后就不再配置后者了。
AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也会被包含 -->
<context:component-scan base-package:"org.example"/>
<beans>
4.使用过滤器进行自定义扫描
默认情况下,类被自动发现并注册bean的条件是:使用@component @repository @service @controller或者使用@Component的自定义注解
可以通过过滤器修改上面的行为,如下xml配置,忽略所有的@resporitory注解(context:exclude-filter
)并用stub代替
<beans>
<context:component-scan base-package:"org.example">
<!--包含过滤器 -->
<context:include-filter type="regex"--通配符
expression=".Stub.*Respository"/>
<!--排除过滤器 -->
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Respository"/>
</context:component-scan>
<beans>
还可以使用user-default-filter:false
禁用自动发现和注册
5.定义bean
6.作用域(scope)
7.spring 代理方式
scoped-proxy 属性指定代理,有三个值可选:no(默认) interface ,target-class
<beans>
<context:component-scan base-package:"org.example" scoped-proxy="interface">
</beans>
1.Required
@Required注解适用于bean属性的setter方法
这个注解仅仅表示,受影响的bean属性**必须在配置时被填充(赋值),**通过在bean定义或通过自动装配一个明确的属性值
public class SimpleMovieLister{
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder=movieFinder;
}
}
2.AutoWired
可以将@AutoWired注解为”传统”的setter方法
private MovieFinder movieFinder;
@AutoWired
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder=movieFinder;
}
也可以用在构造器或成员变量上
@AutoWired
private MovieFinder movieFinder;
private Customer**Dao customer**Dao;
@AutoWired
public ***(Customer**Dao customer**Dao){
this.customer**Dao=customer**Dao;
}
默认情况下,如果因为找不到合适的bean将会导致autowiring失败抛出异常,可以通过在注解上设置required属性为false
@AutoWired(required=false)
public void setXX(XX xx){
this.xx = xx
}
每个类只能有一个构造器被标记为required=true{每个类下可以有多个构造器}
AutoWired的必要属性,建议使用@Required注解(上面情况下用Required代替AutoWired。一般使用AutoWired)
3.@AutoWired和@Resource注解的区别
- Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是
@Resource、@PostConstruct以及@PreDestroy。
- @Resource的作用相当于@Autowired,只不过
@Autowired按byType(即class)
自动注入,而@Resource默认按byName(即ID)自
动注入罢了。 - @Resource有两个属性是比较重要的,分是
name和type
,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。
所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
如果同时指定了
name和type
,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
如果指定了name
,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
如果指定了type
,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
如果既没有指定name,又没有指定type
,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
@Autowired 与@Resource的区别:
- @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上
- @Autowired默认按
类型
装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false)
,如果我们想使用名称装配可以结合@Qualifier注解进行使用 - @Resource(这个注解属于J2EE的),默认按照
名称
进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。 - 使用范围的区别
@AutoWired适用于fields,constructors,multi-argument, methods这些允许在参数级别使用@Qualifier注解缩小范围的情况
@Resource适用于成员变量,只有一个参数的setter方法,所以在目标是构造器或一个多参数方法时,最好的方式是使用qualifiers
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
4.其他用途
可以使用@Autowired注解那些众所周知的解析依赖性接口,比如:BeanFactory,ApplicationContext,Environment,ResourceLoader,ApplicationEventPublisher,MessageSource;
但是Order只对数组有效,对map集合无效
BeanOneImpl 和 BeanTwoImpl都 implements BeanInterface
@Autowired
private List<BeanInterface> list;
//遍历list
for (BeanInterface bean : list) {
System.out.println(bean.getClass().getName());
}
//输出
com.zjx.multibean.BeanTwoImpl
com.zjx.multibean.BeanOneImpl
@Autowired
private Map<String, BeanInterface> map;
//遍历map
for (Map.Entry<String, BeanInterface> entry : map.entrySet()) {
System.out.println(entry.getKey() + " "
+ entry.getValue().getClass().getName());
}
//输出
beanOneImpl com.zjx.multibean.BeanOneImpl
beanTwoImpl com.zjx.multibean.BeanTwoImpl
5.注意
@Autowired是由Spring BeanPostProcessor处理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor类型应用这些注解,这些类型必须通过XML或者Spring的@Bean注解加载
@Qualifier
按类型自动装配可能会有多个bean实例的情况,可以使用Spring的 @Qualifier
注解缩小范围(或指定唯一),也可以用于指定单独的构造器参数或方法参数
// 在BeanInvoker类中增加一个成员变量,因为我们不知道BeanInterface的实现类是哪一个
//(beanOneImpl、beanTwoImpl),通过@Qualifier注解缩小范围为id为”beanTwoImpl”的这个实现类
@Autowired
@Qualifier("beanTwoImpl")
private BeanInterface beanInterface;
@Autowired
private void setComedyCatalog(@Qualifier("对应id") MovieCatalog comedyCatalog){
this.comedyCatalog = comedyCatalog;
}
可以用于注解集合类型变量
如果通过名字进行注解注入,主要是使用的不是@Autowired(即使在技术上能够通过@Qualifier指定bean的名字),替代方式是使用JSR-250@Resource注解,通过其独特的名称来识别特定的目标(这是一个与所声明的类型是无关的匹配过程)
使用@Resource注解,通过唯一名称引用集合或Map的bean
spring用@Autowired注入map出现的问题
当我们用Autowired注入一个map或者其他集合类型时,spring不是根据beanName取bean然后赋值,而是根据设置的type从容器中一次性取出所有符合的bean直接放入到集合中。
【Spring】@Autowired 注入类的集合类型深度解剖