再谈依赖注入(Resourse & Autowired)

2022-03-07  本文已影响0人  MikeShine

1. 写在前面

在 Spring 中,最容易出问题的地方之一就是 “依赖注入”
今天在工作中,遇到了一个问题,

@Resource
private P4pAeAdCampaignDAO p4pAeAdCampaignDAO;

结果最终应用启动的时候,报错:

Bean named 'p4pAeAdCampaignDAO' is expected to be of type 'com.alibaba.global.ad.intl.dao.IntlP4pAeAdCampaignDAO' but was actually of type 'com.sun.proxy.$Proxy276'
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:321)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1268)

今天就结合自己实际使用中遇到的case,来再谈一下依赖注入的问题,主要区别一下 @Resource & @Autowired 的不同。


2. Spring 中的注入

需要明白的是,Spring中的注入事实上是做这样的事情:

因此,需要告诉Spring到底是哪个实现类,这里也是注入的核心点。


3. @Resource & @Autowired

二者都可以用在 Bean 的注入,一般大多数情况(一个接口只有一个实现类)下没有什么区别。

3.1 @Resource 注解

3.2 @Autowired 注解


4. 一个栗子

我们这里看一个例子

// 一个接口
public Interface Human{
        public void dress();
}

// 一个实现 
public class Man Implements Human{
    @Override
    public void dress(){
        sout("Man dress pants");
    }
}

// 注入 
public Controller{
    @Resource
    private Human human;

    @Autowired
    private Human human;
}

不出意外,可以看到两种注入方式都是可以的。

此时,我们增加一个实现类

public Woman Implements Human{
     @Override
    public void dress(){
        sout("woan dress skirts");
    }
}

// 注入
public Controller{
    @Resource
    private Human human;

    @Autowired
    private Human human;
}

由于 Human 有两个实现类,那么这时候就有问题了。两种注入方式都会拿到多个实现类,因此会报错注入Bean失败。

此时可以通过 增加一个 @Qualifier 注解,指明需要装配的实现类变量的名字(Spring是通过变量名去反向拿类名的)。

public Controller{
    @Resource
    @Qualifier("man")
    private Human human;

    @Autowired
    @Qualifier("woman")
    private Human human;
}

或者通过 @Primary 注解给到想要的实现类上,指定 byType 策略首先装配的类。

@Primary
public class Man Implements Human{
    // 具体逻辑
}

事实上,一般都用 @Qualifier 的方法,这样更加灵活。


5. 装配逻辑

@Autowired默认 byType 策略装配,逻辑如下

autowire 注解装配逻辑

@Resource默认 byName 策略装配,无法找到则通过 byType 逻辑装配;逻辑如下

Resource 装配逻辑

回到文章最开始你遇到的问题,为什么遇到这个问题呢,
因为 @Resource 注解默认按照 byName 来找IOC容器中的 Bean,通过 p4pAeAdCampaignDAO 找到了 bean,但是这个 bean 确是 IntlP4pAeAdCampaignDAO 类,就导致与原有的类不匹配,因此跑异常。

上一篇下一篇

猜你喜欢

热点阅读