Spring源码笔记之自动装配以及beanFactory.ignoreDependencyInterface()

beanFactory.ignoreDependencyInterface(Class ifc) 方法

相信很多人在看Spring源码的时候的会看到这个方法,但是不知道这个方法是干嘛的,但是从方法名中我们能够大概知道其功能。

先看下Spring源码中这个接口的注释。
在这里插入图片描述
大概的翻译前面两句话

1
2
3
忽略给定的依赖接口进行自动装配。
通常由应用程序上下文用来注册以其他方式解析的依赖项,
例如通过BeanFactoryAware的BeanFactory或通过ApplicationContextAware的ApplicationContext。

一般官方的解释都比较抽象难理解。想要理解这个方法的作用我们得先了解一下Spring中的一个功能。也是让新手容易混淆的一个功能。

自动绑定(自动装配、Autowiring)

我们得先明确一个事实 @Autowired ≠ 自动绑定(Autowiring)其除了单词长的差不多之外没有其他任何联系

因为很多人看到 自动绑定或者Autowiring就以为是 @Autowired

明确这个事实以后我们得介绍一下这个自动绑定的功能有什么作用?

Autowiring byName和byType的区别

开启自动绑定之后会将我们放入到IOC中的对象自动执行其setter方法,在javaBean中一个属性对应着一个setter和一个getter方法
根据约定setXxx其Xxx把首字母改为小写之后就是这个对象中有的属性名。在开启Spring的自动装配之后,一个放入到IOC中的对象中有setTestBean()方法,如果此时自动绑定的规则是 byName 那么Spring会去IOC中寻找testBean这个对象,如果有的会就会执行该setter方法,如果是byType的方式,就是会寻找当前setter方法里对应的参数类型的bean。如果找到多个同样也是抛出异常。

如果开启 Autowiring?

我们从使用Xml的方式到使用@Bean的方式逐一讲解。

![Xml文件下的类图](https://img-blog.csdnimg.cn/20200522223315463.png?x-oss-process=image/watermark,type_Z
如上图所示,我们在使用XML文件方式的时候涉及到了三个类和一个xml文件 AutowiringTest类中只有一个autowiring方法作为我们测试程序的入口。
在XML文件中我们定义了两个Bean标签,将User和Person放入到了IOC中
Person类关联了User并有setUser(User)方法

XML文件源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
default-autowire="byType"> <!-- 这里是关键,将此上下文中的bean都开启了Autowiring模式 可以改成byName-->

    <bean id="user" class="com.itzijin.dependency.autowiring.domain.User"/>

    <bean id="person" class="com.itzijin.dependency.autowiring.domain.Person"/>

</beans>

Person类和User类

1
2
3
4
5
6
7
8
9
10
11
public class Person {

    private User user;
   
    public void setUser(User user) {
        this.user = user;
    }
}

public class User {
}

AutowiringTest 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@ContextConfiguration("classpath:/META-INF/autowiring-demo.xml")
@RunWith(SpringRunner.class)
public class AutowiringTest {

    @Autowired
    private User user;

    @Autowired
    private Person person;

    @Test
    public void autowiring(){

    }

}

在这里插入图片描述
此时会自动执行该setter方法。并且我们在setUser中对user属性进行了赋值

上面是基于byType的方式,当然也可以修改成byName的方式。按照我之前说的byName和byType的区别可自行进行验证。

如何通过@Bean的方式开启Autowiring呢?

@Bean中有autowire属性。该属性在Spring5.1的时候已经被标记为过时了

在这里插入图片描述

在这里插入图片描述
当前程序的类图变成了这样。其中User和Person仍然没有任何变化,但是却新增了一个AutowiredConfiguration类,该类作为配置类,并且XML文件中也发生了变化,Person这个类不在通过XML文件的方式放入到IOC中而是通过配置类的@Bean来放入到IOC中

AutowiringConfiguration类

1
2
3
4
5
6
7
8
public class AutowiringConfiguration {

    // 指定autowiring的模式为byType
    @Bean(autowire = Autowire.BY_TYPE)
    public Person person() {
        return new Person();
    }
}

在这里插入图片描述

我们可以看到,仍然可以进行自定绑定,不然不得不提的是通过@Bean的方式,只对当前类进行自动绑定,在我们上述例子中。我们Person类放入IOC中的时候@Bean上指定了Autowiring模式。那么就只有Person类有Autowiring的能力,如果想要其他类也有则其他类的@Bean上也要为其指定Autowiring模式

beanFactory.ignoreDependencyInterface(Class ifc) 方法详解

我们了解完Autowiring之后该我们的 beanFactory.ignoreDependencyInterface(Class ifc) 方法上场了。

Spring在org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory方法中有使用到
在这里插入图片描述

我第一次看源码看到这个方法的时候我以为该方法是你在@Autowired的时候不给你进行注入,然而经过我的多方面测试,通过@Autowired仍然能够注入进来,这让我百思不得其解,在网上找了大量资料之后才明白其方法的作用。
这个方法与我们上面讲的Autowiring模式息息相关。

在这里插入图片描述

此时我们的类图变成了这样。其中AutowiringConfiguration新增了一个方法,这个方法将BeanFactoryPostProcessorImpl放入到IOC中

AutowiringConfiguration 类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class AutowiringConfiguration {


    @Bean(autowire = Autowire.BY_TYPE)
    public Person person() {
        return new Person();
    }

    @Bean
    public BeanFactoryPostProcessor beanFactoryPostProcessor() {
        return new BeanFactoryPostProcessorImpl();
    }
}

BeanFactoryPostProcessorImpl类

1
2
3
4
5
6
7
8
9
10
public class BeanFactoryPostProcessorImpl implements BeanFactoryPostProcessor {


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 我们的 beanFactory.ignoreDependencyInterface()方法善良登场了
        beanFactory.ignoreDependencyInterface(Person.class);

    }
}

我们可以看到在 BeanFactoryPostProcessorImpl中我们的 beanFactory.ignoreDependencyInterface()方法善良登场了。

继续运行程序看看有什么不同

在这里插入图片描述

我们发现Person类的setUser(User)方法竟然不执行了?也就是Autowiring模式失效了。

结论

beanFactory.ignoreDependencyInterface() 方法的确是忽略给定接口的自动装配。但是这个自动装配不是 @Autowired