spring-基础六-基于注解配置容器
前言
在开发Spring项目时,经常会发现很多xml配置项,比如接入mybatis时会通过配置对应的xml,将一些数据库链接信息配置好,或者使用redis时通过xml的方式将redis链接信息配置完,但是Spring也提供通过注解的方式配置Spring项目,所以Spring项目应该通过注解配置还是xml方式配置?或者说哪种配置方式更加好?
基于注解的容器配置
基于上面问题查看Spring官网,我们可以清新看到这个问题的探讨:
大致意思是,没有确定的答案,需要看具体的场景,两种方式都有自己的利弊,注解在声明中提供了大量的上下文,导致更简洁的配置,xml配置更擅长于链接组建,而不需要修改他们的源码或者重新编译.
基于注解的配置提供了XML设置的替代方法,它依靠字节码元数据来连接组件,而不是尖括号声明(不需要xml的格式配置),替换使用XML去描述bean,开发者只需移动配置到类本身并通过在关联的类、方法、字段上使用注解.
@Required 注解
@Required注解应用到bean属性的Setter方法,例如:
public class Test {
private BeanA beanA;
@Required
public void setBeanA(BeanA beanA) {
this.beanA = beanA;
}
// ...
}
这个注解表示bean属性在运行时必须被填充赋值,在一个bean定义中显示赋值或自动装配。如果受影响的bean属性没有被填充值容器抛出一个异常。这允许更早的显示异常,避免以后再出现NullPointerException实例等。我们仍然推荐你把断言放入到bean类本身中(例如,放入初始化方法)。这样做会强制执行那些必需的引用和值,即使你在容器外部使用该类也是如此。
注意: @Required注解在Spring5.1中被正式的不推荐使用,更好的方式是,使用构造函数注入要求的设置(或InitializingBean.afterPropertiesSet()的自定义实现以及bean属性设置器方法)。
@Autowired 注解
该注解使用处比较广泛,可以使用在:构造函数,方法,参数,字段上,该注解还有一个参数 required该参数意思为:require=ture 时,表示解析被标记的字段或方法,一定有对应的bean存在.require=false 时,表示解析被标记的字段或方法,没有对应的bean存在不会报错.其默认值为true.
该注解在Spring2.5引入,从Spring4.3开始,如果目标bean仅仅定义以一个构造函数开始,那么构造函数上的@Autowired注解是不必要的。然而,如果有一些构造函数是有效的并且没有主要默认的构造函数,则至少有一个构造函数必须被注解为@Autowired,目的是引导容器选择其中一个去使用。
默认情况下,当没有匹配的候选bean对应给定的注入点的时候自动装配将失败。在这种情况下申明数组、集合或map至少有一个期望匹配的元素。
默认行为是将带注解的方法和字段视为指示所需的依赖项。你可以改变这种行为,像下面这个例子,通过将框架标记为不需要,从而使框架可以跳过不满意的注入点(通过在@Autowired属性中的required设置为false)。说明:满足注意条件就注入,不满足条件就跳过注入。
@Autowired 注解的工作原理
其实在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性.
使用 @Autowired 注解 注意事项
- 在使用@Autowired时,首先在容器中查询对应类型的bean
- 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
- 如果查询的结果不止一个,那么@Autowired会根据名称来查找。
- 如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
@Primary 注解
很多时候我们通过注解需要配置一系列同类型配置,所以可能会出现多个同一类型的实体需要装载,但是Spring并不知道到底需要装配谁,所以引出@Primary注解,先看官网说明:
大致意思是:
因为通过类型的自动装配可能导致多个候选者,通常有必要需要更多的选择处理。一种可以完成的方式是使用Spring的@Primary注解。@Primary表示当多个bean自动装配到单值依赖时这个bean是我们更期望的值。如果主要的bean在限定符候选bean中时,它将被自动装配.
上面例子也很好的说明:Spring会装载firstMovieCatalog,因为其注解@Primary.
同理:在使用xml配置时我们也可以通过 primary = "true" 来表示.
@Qualifiers 注解
@Primary是一种根据类型使用自动装配的有效方法,当可以确定一个主要候选对象时,可以使用多个实例。当你需要更多的控制选择处理时,你可以使用Spring的@Qualifier注解。你可以将限定符值与特定的参数相关联,从而缩小类型匹配的范围,以便每个参数选择特定的bean。
如果你打算试图通过名称表示注解驱动注入,不要主要地使用@Autowired,即使它有通过名称在类型匹配的候选者间选择的能力。相反,使用@Resource注解,它是语义地通过使用唯一名称定义标识一个指定目标组件,声明的类型与匹配过程无关。@Autowired有不同的语义:按类型选择候选bean之后,指定的字符串限定符值仅在那些类型选择的候选中被考虑(例如,匹配一个account限定符与bean被标记相同的限定符标签)。
对于定义为集合、Map、数组类型的bean,@Resource是一个好的解决方案,通过唯一的名称引用指定的集合或数组bean。也就是说,在Spring4.3以后你可以匹配一个Map和数组类型通过Spring的@Autowired类型匹配算法,只要元素类型信息保留在@Bean返回类型签名或集合继承层次结构中。在这种场景中,你可以使用限定符值去相同类型集合选择,如前一段所述。
在Spring4.3以后,@Autowired还考虑了注入的自我引用(也就是说,引用回当前注入的bean)。注意自我注入是一种后备。对其他组件的常规依赖始终优先。从这个意义上说,自我推荐不参与常规的候选人选择,因此尤其是绝不是主要的。相反,它们总是以最低优先级结束。实际上,你应该仅将自我引用用作最后的手段(例如,在相同实例上通过bean的事物代理调用其他方法)。在这种情况下,考虑将受影响的方法分解为单独的委托Bean。或者,你可以使用@Resource,它可以通过其唯一名称获取返回到当前bean的代理。
@Autowired应用到字段、构造函数和多参数方法,在参数级别允许使用限定符注解缩小选择范围。相反,@Resource仅仅支持字段和bean属性Setter方法简单参数。因此,如果注入目标是构造函数或多参数方法,则应坚持使用限定符。
总的来说:@Qualifiers 是来调整自动装配时的条件逻辑,限定Spring在装配时的条件,让自动装配更加精准.
@Resource 注解
source采用一个名字属性。默认情况下,Spring将该值解释为要注入的Bean名称。如果显示指定名称,这个默认名是从字段或Setter方法名获取。如果是字段,则采用字段名称。在使用setter方法的情况下,它采用bean属性名称。在没有明确指定名称的@Resource使用的特殊情况下(类似于@Autowired), @Resource会找到一个主类型匹配而不是一个特定的命名bean,并解析我们熟知的可解析依赖项:BeanFactory、ApplicationContext、 ResourceLoader, ApplicationEventPublisher和MessageSource接口。
对于@Resource 来说:@Resource 注解被用来激活一个命名资源(named resource)的依赖注入,在JavaEE应用程序中,该注解被典型地转换为绑定于JNDI context中的一个对象。 Spring确实支持使用@Resource通过JNDI lookup来解析对象,默认地,拥有与@Resource注解所提供名字相匹配的“bean name(bean名字)”的Spring管理对象会被注入。
@Value 注解
@Value典型的应用去注入外部属性:
@Component
public class BeanA {
private final String test;
public MovieRecommender(@Value("${test.name}") String test) {
this.test = test;
}
}
@Value的值有两类:
- $
就是说,第一个注入的是外部参数对应的property,第二个则是SpEL表达式对应的内容。那个 default_value,就是前面的值为空时的默认值。注意二者的不同。Spring提供的内置转换器支持允许自动处理简单的类型转换(例如,转换为Integer或int)。多个逗号分隔的值能够自动的转换为String数组不需要额外的操作。
@PostConstruct注解和@PreDestroy注解
CommonAnnotationBeanPostProcessor不仅仅识别@Resource注解也能识别JSR-250生命周期注解:javax.annotation.PostConstruct和javax.annotation.PreDestroy。在Spring 2.5中引入的对这些注解的支持为初始化回调和销毁回调中描述的生命周期回调机制提供了一种替代方法。CommonAnnotationBeanPostProcessor在Spring的ApplicationContext中被注入,在生命周期的同一点上(备注:同一类回调方法,比如:销毁方法),与相应的Spring生命周期接口方法或显式声明的回调方法调用带有其中一个注解的方法。在下面的例子中,在以下示例中,缓存在初始化时预先填充,并在销毁时清除。
注意: 类似@Resource一样,@PostConstruct和@PreDestroy注解类型是从JDK6到JDK8的标准Java库的一部分。然而,整个javax.annotation包与JDK 9中的核心Java模块分离,最终在JDK 11中删除。
参考文档
Spring官网
Spring 注解配置(2)——@Autowired
Springboot中@Autowired的原理解析
Spring常用注解@Autowired、@Qualifier