Spring源码系列(一)你真的理解Spring的自动注入吗?

Spring的自动注入,我想任何一个Java的程序员都会无比的自信的说:这个我知道;但是很遗憾的说,笔者理解的自动注入可能与你们理解的自动注入有很大的出入。那我们需要搞清楚Spring的自动注入是什么?自动注入也可以叫自动装配。只是翻译不同,笔者的英文水平有限,这儿就叫自动注入吧!自动注入的对立面就是手动装配。在Spring的程序中,假设你有个A类依赖了B类,这个时候需要在A类添加一个B类的属性。再加上set方法。然后在xml的配置文件中,描述对应的依赖关系。这个时候IOC容器初始化的过程中会实例化A,在实例化A的过程中会填充属性,由于在xml中已经描述好这两者的依赖关系。这个时候Spring会将A类中填充B,这种由程序员自己配置,描述好对应的依赖关系的写法我们称为手动装配具体的例子如下:

package com.ys;

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }
}
package com.ys;

public class B {
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd ">

    <bean id="a" class="com.ys.A">
        <!--由程序员手动指定依赖关系,我们暂且称为手动装配-->
        <property name="b" ref="b"/>
    </bean>

    <bean id="b" class="com.ys.B"/>
</beans>
package com.ys;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext xml = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println(xml.getBean(A.class).getB());
    }
}

运行的结果如下:

在这里插入图片描述

可以看到我们的B类直接注入进去了,但是在现实的情况下:手动装配的应用场景还是比较少的(比如在缺少源码的情况下可能会使用这种手动装配)

关于依赖注入的资料可以参考官网: Dependencies 这个章节提出了一个很重要的面试题,就是Spring的依赖注入的方式有几种?那么这个问题怎么回答呢?官网给了答案,具体如下:

在这里插入图片描述

官网的意思就是:依赖注入(DI)一共有两种主要的变体,分别是基于构造方法的依赖注入和基于set方法的依赖注入,不管是手动装配还是自动装配都是基于这两种方式或者变体的方式来的;这里一定要回答到主要和变体两个名词,因为有的注入方式就不是这两种,而是这两种其中一种变体方式;比如在一个类的属性上面加@Autowired注解,这种方式注入属性的方式就是利用Java反射知识。field.set(value,targetObject)方法,关于这块的源码解析后面博客我会详细说明的。所以@Autowired注入的方式是set注入方式的一种变体。

注意:这里的set方法其实和属性无关,什么意思呢?一般的set方法会对应一个属性进行设置值,但是Spring基于set注入的方式是不需要属性的,仅仅需要一个以set开头的方法,下面举个例子来说明一下:

将原来的A类中代码改成如下所示:

package com.ys;

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setXX(B b) {
        this.b = b;
        System.out.println("spring 找到符合的set方法");
        System.out.println("和属性无关,甚至可以不要属性");
        System.out.println("可以直接调用,这个A里面就没有任何属性");
    }
}


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd ">

    <bean id="a" class="com.ys.A">
        <!--由程序员手动指定依赖关系,我们暂且称为手动装配-->
        <property name="XX" ref="b"/>
    </bean>

    <bean id="b" class="com.ys.B"/>
</beans>

然后我们再运行一下刚才的Main类,看看B这个属性能不能注入进来,具体的结果如下:

在这里插入图片描述

这个时候可以看到我们的B的属性注入进去了。

可能有读者会认为是笔者改了xml的配置文件,这个时候肯定会调用setXX的方法,其实不然,即使我使用自动装配也还是会调用的(关于什么是自动装配,下文会介绍)因为前文说过,注入方式与手动注入,自动注入无关。笔者改下代码,把A的注入模型改成自动注入。具体代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd ">

    <!--程序员不指定装配的参数,容器自动查询后装配-->
    <bean id="a" class="com.ys.A" autowire="byType"/>

    <bean id="b" class="com.ys.B"/>
</beans>

具体的运行结果如下:

在这里插入图片描述

可以看到B的属性已经注入进去了,把代码改成上面的自动装配的结果是一样的,A类当中的setXX方法还是会调用,不需要提供任何属性,至于原理笔者后面讲Spring的源码会详细的说明;可能会有读者会说如果使用注解呢?比如以下的代码:

package com.ys.anno;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {

    @Autowired
    private B b;

    public B getB() {
        return b;
    }

    public void setXX(B b) {
        //this.b = b;
        System.out.println("spring 找到符合的set方法");
        System.out.println("和属性无关,甚至可以不要属性");
        System.out.println("可以直接调用,这个A里面就没有任何属性");
    }
}
package com.ys.anno;

import org.springframework.stereotype.Component;

@Component
public class B {
}
package com.ys.anno;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.anno")
public class AppConfig {
}
package com.ys.anno;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext anno = new AnnotationConfigApplicationContext(AppConfig.class);
        System.out.println(anno.getBean(A.class).getB());
    }
}

运行的结果如下:

在这里插入图片描述

可以发现并没有调用set方法。上面的代码同样是注入b,但是是通过filed.set方法去注入的。不是通过set方法,当然再次说明一下这是set方法的一种变体;上面代码直到A完成注入B后set方法也不会调用。

重点来了,笔者看过很多资料说@Autowired也算自动装配,关于这点笔者不敢苟同,在一个属性上面加@Autowired注解应该属于手动装配,笔者会通过对应的源码和例子来证明。

很多人认为@Autowired注解是先byType然后再byName。很可惜这个说法是错误的。笔者见过很多程序员和很多资料都支持这种说法。而byType仅仅是一种自动注入的模型而已,这种模型有其固有的技术手段,而@Autowired注解会被Spring的后置处理器解析,和处理byType不是同一回事。

如果需要讲清楚他们的区别和证明@Autowired不是自动装配则首先要搞明白什么自动装配。笔者接下来会花一定篇幅来解释自动装配的知识,然后回过头来讲他们的区别和证明@Autowired属性是手动装配。

前面笔者已经介绍了手动装配也叫手动注入,也理解了注入的方式(set方法和构造方法)那么接下来我们讨论自动注入或者叫自动装配。

自动注入的出现是因为手动注入过于麻烦,比如一个类中依赖了过多的属性,这个时候配置文件就比较臃肿,Spring的做法就是可以为这个类提供一种叫做自动注入的模型,无需程序员去手动配置这个类的依赖关系。这时候,有读者会疑问,用注解不是可以解决xml臃肿的问题吗?确实可以用注解来解决这个问题,但是我们现在讨论的是自动装配的问题。就不能用注解;为什么不能用注解来讨论自动装配的问题呢?因为在不配置BeanFactoryPostProcessor和修改beanDefinition的情况下注解的类是不支持自动装配的,下面我会证明,这也是证明@Autowired默认不是自动装配的一个证据,下文我会解释一个注解类默认是不支持自动装配的。也就是说如果讨论自动装配最好是用xml形式来配置Spring容器才会有意义;比如下面的例子:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd " 
       default-autowire="byType">

    <!--default-autowire="byType"-->
	<!-- 程序员不指定装配的具体参数,容器自动查询后装配-->
	<!--当然除了这种写法还可以直接在bean标签上为特定类指定自动装配模型-->
    <bean id="a" class="com.ys.xml.A" />

    <bean id="b" class="com.ys.xml.B"/>
</beans>
package com.ys.xml;

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setXX(B b) {
        this.b = b;
    }
}
package com.ys.xml;

public class B {
}
package com.ys.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext xml = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println(xml.getBean(A.class).getB());
    }
}

运行的结果如下

在这里插入图片描述

可以发现我们的A中B的属性注入成功了,但是我们的xml的配置文件中并没有维护他们直接的依赖关系,而是我们只加了一行default-autowire=“byType”,其实关于自动注入的歧义或者被人误解的地方就是这个default-autowire=“byType”引起,那么这行配置是什么意思呢?这里意思表示配置的xml的文件中的所有的bean都是以byType这种模式自动装配(如果没有特殊的指定,因为bean还可以单独配置装配模式的)这东西是有理有据的,具体可以看Spring官网中的 Bean Overview 具体的内容如下:

在这里插入图片描述

在这里插入图片描述

任何行业概念很重要,不然沟通都会有困难,Autowiring modes 笔者暂且翻译成自动注入(自动装配)的模型吧。当然可能会有更好的翻译,这儿笔者就翻译成自动注入吧。

注意:这儿的自动注入模型和前面提到的依赖注入的方式(set方法和构造方法)是两回事。简而言之:依赖注入是一个过程,主要通过set方法和构造方法以及一些变体的方法完成对对象的依赖或者填充上这个过程叫做依赖注入,不管是手动装配还是自动装配都是这个过程。而自动装配的模型是一种完成自动装配依赖的手段的体现,每一种模型都使用了不同的技术去查找和填充bean,从Spring的官网上可以看到Spring只提出了4种自动装配的模型(严格意义上只有三种,因为第一种是no,表示不使用自动装配(默认))这四种模型在源码上体现是一个整形来表示的,其中no用0来表示;byName用1来表示,byType用2表示,constructor用3表示,具体如下:

在这里插入图片描述

那么@Autowired是自动装配吗?我们可以通过打印autowireMode的值查看一下是什么的模型,而autowireMode是BeanDefinition中定义的,那我们怎么取出来呢?我们可以通过实现BeanFactoryPostProcessor的接口来取出这个值,具体的代码如下:

package com.ys.anno;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {

    @Autowired
    private B b;

    public B getB() {
        return b;
    }
}
package com.ys.anno;

import org.springframework.stereotype.Component;

@Component
public class B {
}
package com.ys.anno;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.anno")
public class AppConfig {
}
package com.ys.anno;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

@Component
public class ABeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("a");
        System.out.println("AutowireMode:" + genericBeanDefinition.getAutowireMode());
    }
}
package com.ys.anno;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext anno = new AnnotationConfigApplicationContext(AppConfig.class);
        System.out.println(anno.getBean(A.class).getB());
    }
}

运行的结果如下:

在这里插入图片描述

可以看到这儿是0,也就是不是自动装配了。其实这已经能证明@Autowried不是自动装配了,但是还有更直接的证据证明他不是自动装配,就是通过Spring源码当中处理@Autowried的代码可以看出,博客后面的部分会有讲的。下面我们再来看下xml的打印是什么,具体的代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd " default-autowire="byType">


    <!--程序员不指定装配的参数,容器自动查询后装配-->
    <bean id="a" class="com.ys.xml.A" />

    <bean id="b" class="com.ys.xml.B"/>

    <bean id="aBeanFactoryPostProcessor" class="com.ys.xml.ABeanFactoryPostProcessor"/>
</beans>
package com.ys.xml;

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setXX(B b) {
        this.b = b;
    }
}
package com.ys.xml;

public class B {
}
package com.ys.xml;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;

public class ABeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("a");
        System.out.println("AutowireMode:" + genericBeanDefinition.getAutowireMode());
    }
}
package com.ys.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext xml = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println(xml.getBean(A.class).getB());
    }
}

运行的结果如下:

在这里插入图片描述

可以看到上面打印的autowireMode的值为2。这时候我们通过源码的方式来证明,还是上面的代码,我们需要将ABeanFactoryPostProcessor从容器中剔除出去。然后在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean方法打上断点,这个方法主要就是完成属性填充的,也就是大家说的注入

在这里插入图片描述

在这里插入图片描述

可以看到上面有个判断,判断当前类的注入模式是否是byName或者byType如果是其中一个就直接进入这个判断,执行对应的自动装配的逻辑;因为当前代码我在xml当中配置了自动注入模型为bytype所以这里一定会进入。具体如下图:

在这里插入图片描述

通过上面录制的GIF图,可以看到断点最后进入了if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) 这个判断中去了,这就是自动装配的模型选择byType然后我们再调试一下@Autowired注解的代码,具体如下图:

在这里插入图片描述

从上面的GIF图我们可以看到对应的用@Autowired注解时候,直接跳过对应的两个判断了,所以再一次说明@Autowired注解不是自动装配模型中的byType或者是byName。之前在和朋友讨论的时候,出现了下面这种情况,具体的代码如下:

package com.ys.anno;

import org.springframework.stereotype.Component;

@Component
public class A {

    private B b;

    public B getB() {
        return b;
    }

    public A(B b) {
        this.b = b;
    }
}
package com.ys.anno;

import org.springframework.stereotype.Component;

@Component
public class B {
}
package com.ys.anno;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.anno")
public class AppConfig {
}
package com.ys.anno;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext anno = new AnnotationConfigApplicationContext(AppConfig.class);
        System.out.println(anno.getBean(A.class).getB());
    }
}

运行的结果如下:

在这里插入图片描述

难道这个是自动装配吗?是基于构造器注入吗?我们继续看源码证明。具体的如下:

在这里插入图片描述

上面最关键的代码就是

if (ctors != null || mbd.getResolvedAutowireMode() ==
AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args);
}

这里有个判断 首先判断 ctors != null 然后判断类的自动注入模型是不是等于AUTOWIRE_CONSTRUCTOR也就是3;分两种情况来分析:

  • 第一种情况:假设你指定了类的自动注入模型为constructor那么这个if一定成立因为他是||判断只要一个成立整个if成立;很显然我们这里不是这种情况,笔者并没有指定A类的自动注入模型为3,上面的那个gif里面我给读者展示了,后面那个判断不成立,因为mbd.getResolvedAutowireMode()=0;再一次说明了一个注解类默认的自动注入模型为no也就是autowireMode=0;
  • 第二种情况:没有指定类的自动注入模型,笔者代码例子就是这种情况,那么Spring会首先推断出构造方法,笔者A里面一个带参数的构造方法,所以再进行第一个判断ctors!= null的时候就已经成立了,于是也会进入
  • 结论:在一个注解类里面提供了一个构造方法之所以能达到和自动注入的效果一样并不是因为这种方式就是自动装配,而是因为Spring源码当中做了判断;使这种情况下调用的代码和自动装配调用的逻辑一下。但是有的读者会说那这样也能算自动装配啊,当然如果读者一定这么认为那么也无可厚非;仁者见仁;智者见智

逼逼了这么久了@Autowried到底和byType有什么关系呢?为什么有资料会把他们联系在一起呢?

首先byType是一种自动注入模型,Spring会根据类型去查找一个符合条件的bean,如果没找到则不注入,程序不会报错;如果找到多个,Spring也会报错。比如你有个接口I,提供两个实现I1和I2都存在容器当中,然后在A类当中去注入I,并且指定自动注入模型为byType那么这个时候会找到两个符合条件的bean,Spring就迷茫了,注入哪个呢?Spring哪个都不注入直接抛出异常;但是如果找到了一个那么注入的时候会调用set方法;具体的代码如下:

package com.ys.xml;

public interface I {
}
package com.ys.xml;

public class I1 implements I{
}
package com.ys.xml;

public class I2 implements I{
}
package com.ys.xml;

public class A {

    private I i;

    public void setI(I i) {
        this.i = i;
    }

    public I getI() {
        return i;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd "
       default-autowire="byType">

    <!--程序员不指定装配的参数,容器自动查询后装配-->
    <bean id="a" class="com.ys.xml.A" />

    <bean id="i1" class="com.ys.xml.I1"/>

    <bean id="i2" class="com.ys.xml.I2"/>

</beans>
package com.ys.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext xml = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println(xml.getBean(A.class).getI());
    }
}

运行的结果如下:

在这里插入图片描述

然后我们再来看下@Autowried注解的情况。

Spring会首先根据属性的类型去容器中找,如果没有找到在根据属性的名字找,找到了则注入,没有找到则异常,下面的代码就是容器当中没有一个符合的类型和名字就抛出异常;

package com.ys.anno;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {

    @Autowired
    private I i;

    public I getI() {
        return i;
    }
}
package com.ys.anno;

public interface I {
}

package com.ys.anno;

import org.springframework.stereotype.Component;

@Component
public class I1 implements I {

}
package com.ys.anno;

import org.springframework.stereotype.Component;

@Component
public class I2 implements I {
}
package com.ys.anno;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.anno")
public class AppConfig {
}
package com.ys.anno;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext anno = new AnnotationConfigApplicationContext(AppConfig.class);
        System.out.println(anno.getBean(A.class).getI());
    }
}

运行结果如下:

在这里插入图片描述

如果先根据类型找到了一个,那么直接注入,下面的代码就是只有一个符合要求的类型能够完美注入;我们只需要修改 I1的代码,具体如下:

package com.ys.anno;

import org.springframework.stereotype.Component;

public class I1 implements I {

}

运行结果如下:

在这里插入图片描述

如果先根据类型找到了多个,那么Spring不会立马异常,而是根据名字再找去找,如果根据名字找到一个合理的则注入这个合理的,下面的代码就是I1和I2都符合,但是Spring最后却没有异常,是因为属性名字叫i1故而先类型在名字找到了合理的,我们修改相应的代码

package com.ys.anno;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {

    @Autowired
    private I i1;

    public I getI() {
        return i1;
    }
}

运行结果如下:

在这里插入图片描述

如果先根据类型找到了多个,那么Spring不会立马异常,而是根据名字再找去找,如果根据名字还是没有找到那么时候Spring会异常,下面的代码就是两个i1和i2都符合,于是Spring通过名字找i3也找不到,故而出异常;修改的代码如下:

package com.ys.anno;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {

    @Autowired
    private I i3;

    public I getI() {
        return i3;
    }
}

运行结果如下:

在这里插入图片描述

以后如果再听到@AutowriedbyType请你纠正他,byType是一种自动注入模型;@Autowried是一个注解,两个东西没有关系,一点关系都没有;@Autowried讲道理算是手动装配;那么一个注解的类到底能不能开启自动装配呢?答案是可以的,我们只需要修改BeanDefinition中的AutowireMode属性具体的代码如下:

package com.ys.anno;

import org.springframework.stereotype.Component;

@Component
public class A {

   private B b;

    public B getB() {
        return b;
    }
    
     public void setB(B b) {
        this.b = b;
    }
}
package com.ys.anno;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.anno")
public class AppConfig {
}
package com.ys.anno;

import org.springframework.stereotype.Component;

@Component
public class B {
}
package com.ys.anno;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

@Component
public class ABeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("a");
        //设置为byType
        genericBeanDefinition.setAutowireMode(2);
        System.out.println("AutowireMode:" + genericBeanDefinition.getAutowireMode());
    }
}
package com.ys.anno;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext anno = new AnnotationConfigApplicationContext(AppConfig.class);
        System.out.println(anno.getBean(A.class).getB());
    }
}

运行结果如下:

在这里插入图片描述

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值