美文网首页
再谈依赖注入(Resourse & Autowired)

再谈依赖注入(Resourse & Autowired)

作者: MikeShine | 来源:发表于2022-03-07 11:45 被阅读0次

    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 会替换该引对象用为特定的实现类

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


    3. @Resource & @Autowired

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

    3.1 @Resource 注解

    • 是 JDK 本身带有的注解,在 Annotation 包下。
    • 默认通过 Bean Name 进行装配(反射机制)
    • name & type 属性,可以指定 byName / byType 机制装配

    3.2 @Autowired 注解

    • 是 Spring 框架带的注解
    • 默认通过 byType 的模式进行装配
    • 可以通过 @Qualifier & @Primary 进行指定

    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 类,就导致与原有的类不匹配,因此跑异常。

    相关文章

      网友评论

          本文标题:再谈依赖注入(Resourse & Autowired)

          本文链接:https://www.haomeiwen.com/subject/ouzgrrtx.html