本文主要介绍了对Spring中的自动组装和自动连接注释的使用的全面理解。边肖认为这很好。现在分享给大家,给大家一个参考。来和边肖一起看看吧。
一、自动装配
当Spring组装Bean属性时,有时很明显需要组装一个Bean对指定属性的引用。例如,如果在我们的应用程序上下文中只有一个org . mybatis . spring . SqlSessionFactoryBean类型的Bean,那么任何依赖于sqlsessionfactoryBean的其他Bean都需要这个Bean。毕竟这里只有一个SqlSessionFactoryBean的Bean。
为了处理这种清晰的组装场景,Spring提供了自动装配。与其显式组装Bean属性,为什么不让Spring识别可以自动组装的场景。
当谈到自动组装Bean依赖项时,Spring有许多方法来处理它。因此,Spring提供了四种自动组装策略。
公共接口AutowireCapableBeanFactory{
//不需要自动装配
int AUTOWIRE _ NO=0;
//按名称自动组装bean属性
int AUTOWIRE _ BY _ NAME=1;
//按类型自动组装bean属性
int AUTOWIRE _ BY _ TYPE=2;
//根据构造函数自动组装
int auto wire _ CONSTRUCTOR=3;
//过时的方法,Spring3.0以后不再支持
@已弃用
int auto wire _ auto detect=4;
}
这些策略在Spring AutowireCapableBeanFactory的接口中定义。其中AUTOWIRE_AUTODETECT被标记为过时方法,Spring3.0以后不再支持。
1、byName
意味着与bean的属性同名的其他bean被自动组装成bean的相应属性。这听起来可能有点拗口。让我们看一个例子。
首先在User的Bean中有一个属性Role myRole,然后创建一个Role的Bean。如果它的名字是myRole,那么byName可以用在User中进行自动组装。
公共类用户{
私人角色myRole
}
公共类角色{
私有字符串id;
私有字符串名称;
}
以上是Bean的定义,接下来看配置文件。
bean id= my role class= com . view scenes . net supervisor . entity . role
属性名=id 值= 1001 /属性
属性=名称值=管理员/属性
/bean
bean id= user class= com . view scenes . net supervisor . entity . user auto wire= by name /bean
如上所述,只要属性的名称和Bean的名称能够对应,那么就可以在用户的Bean中使用byName进行自动组装。那么,如果属性名不对应呢?
2、byType
可以,如果不使用属性名对应,也可以选择使用类型自动组装。意味着与bean的属性类型相同的其他bean被自动组装成bean的相应属性。
bean class= com . view scenes . net supervisor . entity . role
属性名=id 值= 1001 /属性
属性=名称值=管理员/属性
/bean
bean id= user class= com . view scenes . net supervisor . entity . user auto wire= by type /bean
在上面的例子中,如果使用byType,可以省略角色Bean的ID。
3、constructor
也就是说,与bean构造函数参数同类型的其他Bean被自动组装成Bean构造函数的相应参数。注意,具有相同类型的其他bean表明,它是在查找参数时由bean的类型决定的。
构造函数中的参数类型是Role。
公共类用户{
私人角色角色;
公共用户(角色role) {
this.role=role
}
}
bean id= user class= com . view scenes . net supervisor . entity . user auto wire= constructor /bean
4、autodetect
首先,它会尝试使用构造函数进行自动组装,如果失败,则尝试使用byType。但在Spring3.0之后已经标记为@Deprecated。
5、默认自动装配
默认情况下,default-autowire属性设置为none,表示所有bean都不使用自动装配,除非在bean上配置了autowire属性。
如果您需要为所有Bean配置相同的autowire属性,有一种方法可以简化此操作。
在根元素Beans上添加属性default-autowire=byType。
beans默认值-autowire=byType
弹簧自动装配的优势不言而喻。但实际上不建议在Spring XML配置文件中自动组装,作者认为最大的缺点在于不确定性。或者除非你对整个Spring应用中的所有豆子了如指掌,随着豆子的增多和关系复杂度的增加,情况可能会很糟糕。
第二,自动连线
从Spring2.5开始,支持注释来自动组装Bean属性。它允许更细粒度的自动组装,我们可以有选择地标记某个属性来对其应用自动组装。
Spring支持几种不同的自动装配注释。
Spring自带的@Autowired注释。
JSR-330的@Inject注释。
@ JSR-250资源评论。
今天,我们只关注自动连线注释。其解析和注入过程请参考作者的Spring source系列文章。Spring源代码分析(2) bean实例化和IOC依赖注入
使用@Autowired非常简单,只需在需要注入的属性中添加注释即可。
@自动连线
UserService用户服务;
但是,在使用时有几点需要注意。
1.命令的
默认情况下,它具有强制契约的特征,其标记的属性必须是可组装的。如果没有Bean可以组装到由Autowired标记的属性或参数中,那么您将会看到nosuchbeandidefinitionexception的异常消息。
公共对象doResolveDependency(dependency descriptor描述符,字符串beanName,
SetString autowiredBeanNames,TypeConverter typeConverter)抛出bean异常{
//查找Bean
MapString,Object matching beans=findAutowireCandidates(bean name,type,descriptor);
//如果获取的Bean集合为空并且是必需的,则引发异常。
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
raisenosuchbean definitionexception(类型,,描述符);
}
返回null
}
}
看到上面的源代码,我们可以得到这些信息。Bean集是否为空无关紧要,key isRequired条件无法成立。然后,如果我们不确定属性是否可以组装,我们可以像这样使用Autowired。
@自动连线(必需=假)
UserService用户服务;
2、装配策略
记得有个面试问题曾经问过:Autowired自动组装是什么策略?
在这个问题上,我们不能一概而论。不能简单的按类型或者按名字来说。但可以肯定的是,默认是按照类型自动组装的,也就是byType。
按默认类型装配。
关键点是findAutowireCandidates。
受保护的MapString,Object findAutowireCandidates(
字符串beanName,Class。requiredType,DependencyDescriptor描述符){
//获取给定类型的所有bean名称,这实际上是循环所有beanName并获取其实例。
//然后用isTypeMatch方法确定。
string[]candidateNames=beanfactoryutils . beannamesfortype including ancestors(
this,requiredType,true,descriptor . iseager());
MapString,Object result=new LinkedHashMapString,Object(candidatenames . length);
//根据返回的beanName,获取其实例返回。
for(String candidateName:candidateNames){
如果(!isSelfReference(beanName,candidateName)isAutowireCandidate(candidateName,descriptor)) {
result.put(candidateName,get bean(candidateName));
}
}
返回结果;
}
按名字集合
可以看出,它返回了一个列表,表明根据类型匹配可能会查询到多个实例。应该组装哪个实例?我看了一些文章,你可以添加评论来避免它。比如@ qulifer、@Primary等。其实有一个简单的方法。
例如,根据UserService接口类型组装它的实现类。UserService接口有几个实现类,包括UserServiceImpl和UserServiceImpl2。然后当我们注入时,我们可以将属性名定义为Bean实现类的名称。
@自动连线
UserService UserServiceImpl2
在这种情况下,Spring将根据byName进行组装。首先,如果发现该类型的多个实例,Spring已经做出了判断。
公共对象doResolveDependency(dependency descriptor描述符,字符串beanName,
SetString autowiredBeanNames,TypeConverter typeConverter)抛出豆异常{
//按照类型查找豆实例
MapString,对象匹配bean=findAutowireCandidates(bean名称,类型,描述符);
//如果豆集合为空,且是必需的成立就抛出异常
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
raisenosuchbean定义异常(类型,,描述符);
}
返回空
}
//如果查找的豆实例大于一个
if (matchingBeans.size() 1) {
//找到最合适的那个,如果没有合适的。也抛出异常
string主bean name=determineAutowireCandidate(匹配bean,描述符);
if (primaryBeanName==null) {
抛出新的nouniquebeandidefinitionexception(类型,匹配项。keyset());
}
if (autowiredBeanNames!=null) {
autowiredbean名称。添加(主bean名称);
}
返回配套豆。get(主bean名称);
}
}
可以看出,如果查到多个实例,确定自动线候选人方法就是关键。它来确定一个合适的豆返回。其中一部分就是按照豆的名称来匹配。
受保护的字符串determineAutowireCandidate(MapString,Object candidateBeans,
依赖描述符描述符){
//循环拿到的豆集合
对于(图EntryString,对象条目:候选beans。条目集()){
字符串candidatebean name=entry。getkey();
对象bean实例=条目。getvalue();
//通过matchesBeanName方法来确定豆集合中的名称是否与属性的名称相同
if(匹配bean名称(candidatebean名称,描述符。getdependency name()){
返回候选人姓名
}
}
返回空
}
最后我们回到问题上,得到的答案就是:@自动连线默认使用按类型来装配属性,如果匹配到类型的多个实例,再通过绰号来确定豆子。
3、主和优先级
上面我们已经看到了,通过按类型可能会找到多个实例的豆子。然后再通过绰号来确定一个合适的豆子,如果通过名称也确定不了呢?
还是determineAutowireCandidate这个方法,它还有两种方式来确定。
受保护的字符串determineAutowireCandidate(MapString,Object candidateBeans,
依赖描述符描述符){
班级?必需的类型=描述符。getdependencytype();
//通过@主要注解来标识豆
string primary candidate=determinePrimaryCandidate(候选beans,必选类型);
if (primaryCandidate!=null) {
返回初选候选人
}
//通过@优先级(值=0)注解来标识豆值为优先级大小
string priority candidate=determineHighestPriorityCandidate(候选beans,必选类型);
如果(优先级候选人!=null) {
返回优先候选人
}
返回空
}
Primary
它的作用是看豆上是否包含@主要注解,如果包含就返回。当然了,你不能把多个豆都设置为@初级,不然你会得到nouniquebeandidefinitionexception这个异常。
受保护的字符串determinePrimaryCandidate(MapString,Object candidateBeans,Class?requiredType) {
String primaryBeanName=null
对于(图EntryString,对象条目:候选beans。条目集()){
字符串candidatebean name=entry。getkey();
对象bean实例=条目。getvalue();
if (isPrimary(candidateBeanName,beanInstance)) {
if (primaryBeanName!=null) {
布尔candidateLocal=包含bean定义(candidatebean名称);
布尔主本地=包含bean定义(主bean名称);
if(candidateLocal primaryLocal){
抛出新的nouniquebeandidefinitionexception(必需类型,candidateBeans.size(),
在候选项中找到多个"主”豆子:“candidatebeans。keyset()";
}
else if (candidateLocal) {
主bean名称=candidatebean名称;
}
}
否则{
主bean名称=candidatebean名称;
}
}
}
返回primaryBeanName
}
优先
你也可以在豆上配置@优先级注解,它有个(同国际组织)国际组织类型的属性值,可以配置优先级大小。数字越小的,就被优先匹配。同样的,你也不能把多个豆的优先级配置成相同大小的数值,否则nouniquebeandidefinitionexception异常照样出来找你。
受保护的字符串determineHighestPriorityCandidate(MapString,Object candidateBeans,
班级?requiredType) {
string highestprioritybean name=null;
整数highestPriority=null
对于(图EntryString,对象条目:候选beans。条目集()){
字符串candidatebean name=entry。getkey();
对象bean实例=条目。getvalue();
整数候选优先级=get优先级(bean实例);
if (candidatePriority!=null) {
if (highestPriorityBeanName!=null) {
//如果优先级大小相同
如果(候选人优先。等于(最高优先级)){
抛出新的nouniquebeandidefinitionexception(必需类型,candidateBeans.size(),
找到多个具有相同优先级的豆子(“最高优先级")
候选人中: candidatebeans。keyset());
}
else if(候选优先级最高优先级){
highestprioritybean name=candidatebean name;
最高优先级=候选优先级;
}
}
否则{
highestprioritybean name=candidatebean name;
最高优先级=候选优先级;
}
}
}
返回highestPriorityBeanName
}
最后,有一点需要注意106 .优先事项的包在javax。注释。优先级;如果想使用它还要引入一个坐标。
属国
groupIdjavax.annotation/groupId
artifactId javax。注释-API/artifactId
版本1.2/版本
/依赖关系
三、总结
本章节重点阐述了春天中的自动装配的几种策略,又通过源码分析了自动连线注解的使用方式。
在Spring3.0之后,有效的自动装配策略分为按类型、按名称、构造函数三种方式。注解自动连线默认使用按类型来自动装配,如果存在类型的多个实例就尝试使用绰号匹配,如果通过绰号也确定不了,可以通过主要的和优先注解来确定。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。