Spring中Autowired的自动装配

自动装配

        spring会在上下文中自动查找Bean并注入到IOC容器中。


spring提供了四种自动装配策略

public interface AutowireCapableBeanFactory{

    //无需自动装配
    int AUTOWIRE_NO = 0;

    //按名称自动装配bean属性
    int AUTOWIRE_BY_NAME = 1;

    //按类型自动装配bean属性
    int AUTOWIRE_BY_TYPE = 2;

    //按构造器自动装配
    int AUTOWIRE_CONSTRUCTOR = 3;

    //过时方法,Spring3.0之后不再支持
    @Deprecated
    int AUTOWIRE_AUTODETECT = 4;
}

1.ByName(按名称自动装配):

        把与 bean 的属性具有相同名字的其他 bean 自动装配到 bean 的对应属性中

 定义一个实体类并定义属性:

public class User{
    private Role myRole;
}
public class Role {
    private String id;  
    private String name;
}

 那么在configContext配置文件中的应该这样注入:

//用我们自定义的属性名注入IOC容器,class为类的完全限定名。

<bean id="myRole" class="com.viewscenes.netsupervisor.entity.Role">
    <property name="id" value="1001"></property>
    <property name="name" value="管理员"></property>
</bean>

<bean id="user" class="com.viewscenes.netsupervisor.entity.User" autowire="byName"></bean>

 2.ByType

        把与 bean 的属性具有相同类型的其他 bean 自动装配到 bean 的对应属性中。

<bean id="myRole" class="com.viewscenes.netsupervisor.entity.Role">
    <property name="id" value="1001"></property>
    <property name="name" value="管理员"></property>
</bean>

<bean id="user" class="com.viewscenes.netsupervisor.entity.User" autowire="byName"></bean>

3.Constructor

        把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器的对应入参中。值的注意的是,具有相同类型的其他Bean这句话说明它在查找入参的时候,还是通过Bean的类型来确定。

public class User{
    private Role role;

    public User(Role role) {
        this.role = role;
    }
}

<bean id="user" class="com.viewscenes.netsupervisor.entity.User" autowire="constructor"></bean>

4、autodetect

        它首先会尝试使用constructor进行自动装配,如果失败再尝试使用byType。不过,它在Spring3.0之后已经被标记为@Deprecated


@Autowired注解

        从spring2.5开始,支持使用注解来自动装配bean属性,他允许更细粒度的属性装配,我们可以选择某一个属性来添加Autowired注解。

使用@Autowirded注解:

//在需要注入的属性前添加注解即可

@Autowired

UserService userService;

@Autowirded的几种特性:

1.强制性 

        默认情况下,它具有强制契约的特性,就是所标注的属性必须是可装配的,如果没有bean可以装配的属性,就会报错:NoSuchBeanDefinitionException

public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
            Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
    
    // 查找Bean
    Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    // 如果拿到的 Bean 集合为空,且 isRequired 为 true,就抛出异常
    if (matchingBeans.isEmpty()) {
        if (descriptor.isRequired()) {
            raiseNoSuchBeanDefinitionException(type, "", descriptor);
        }
        return null;
    }
}

 2.装配策略

(1)默认按照类型装配(findAutowireCandidates方法)

protected Map<String, Object> findAutowireCandidates(
        String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
    
    // 获取给定类型的所有 bean 名称,里面实际循环所有的 beanName,获取它的实例
    // 再通过 isTypeMatch 方法来确定
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this, requiredType, true, descriptor.isEager());
            
    Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
    
    // 根据返回的 beanName,获取其实例返回
    for (String candidateName : candidateNames) {
        if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
            result.put(candidateName, getBean(candidateName));
        }
    }
    return result;
}

(2)按照类型没有找到时,按照名称装配

        如果查到多个实例时,就会使用determineAutowireCandidate方法,即按照名称查询并装配。

protected String determineAutowireCandidate(Map<String, Object> candidateBeans, 
                DependencyDescriptor descriptor) {

    // 循环拿到的 bean 集合
    for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
        String candidateBeanName = entry.getKey();
        Object beanInstance = entry.getValue();
        // 通过 matchesBeanName 方法来确定 bean 集合中的名称是否与属性的名称相同
        if (matchesBeanName(candidateBeanName, descriptor.getDependencyName())) {
            return candidateBeanName;
        }

    }
    return null;
}

(3)主和优先级

        如果既不能通过ByType装配,又不能通过ByName装配,就会使用determaneAutowiredCandidate 方法。

protected String determineAutowireCandidate(Map<String, Object> candidateBeans, 
                DependencyDescriptor descriptor) {
    Class<?> requiredType = descriptor.getDependencyType();
    // 通过 @Primary注解来标识 bean
    String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
    if (primaryCandidate != null) {
        return primaryCandidate;
    }
    // 通过 @Priority(value = 0) 注解来标识 bean, value 为优先级大小
    String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
    if (priorityCandidate != null) {
        return priorityCandidate;
    }
    return null;
}

通过俩种注解实现:

@primary

protected String determineAutowireCandidate(Map<String, Object> candidateBeans, 
                DependencyDescriptor descriptor) {
    Class<?> requiredType = descriptor.getDependencyType();
    //通过@Primary注解来标识Bean
    String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
    if (primaryCandidate != null) {
        return primaryCandidate;
    }
    //通过@Priority(value = 0)注解来标识Bean value为优先级大小
    String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
    if (priorityCandidate != null) {
        return priorityCandidate;
    }
    return null;
}

@Priority

protected String determinePrimaryCandidate(Map<String, Object> candidateBeans, Class<?> requiredType) {
    String primaryBeanName = null;
    for (Map.Entry<String, Object> entry : candidateBeans.entrySet()) {
        String candidateBeanName = entry.getKey();
        Object beanInstance = entry.getValue();
        if (isPrimary(candidateBeanName, beanInstance)) {
            if (primaryBeanName != null) {
                boolean candidateLocal = containsBeanDefinition(candidateBeanName);
                boolean primaryLocal = containsBeanDefinition(primaryBeanName);
                if (candidateLocal && primaryLocal) {
                    throw new NoUniqueBeanDefinitionException(requiredType, candidateBeans.size(),
                            "more than one 'primary' bean found among candidates: " + candidateBeans.keySet());
                }
                else if (candidateLocal) {
                    primaryBeanName = candidateBeanName;
                }
            }
            else {
                primaryBeanName = candidateBeanName;
            }
        }
    }
    return primaryBeanName;
}

Autowired实现原理总结:

  1. 在Spring3.0后,自动装配策略分为三种:ByType,By Name , constructor三种方式。
  2. 默认按照类型装配,如果存在多个实例,则按照ByName匹配,如果依旧确定不了,则按照prority或primany 注解来确定。

参考文章:https://www.jianshu.com/p/2f1c9fad1d2d

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

#0000FF格子衫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值