spring源码系列——毁三观的spring自动注入(下)

我是子路,一个靠Java吃饭的男人。

接上篇文章:spring源码系列——毁三观的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">

        <bean id="a" class="com.luban.app.A">
        </bean>
        <bean id="b"  class="com.luban.app.B">
        </bean>
</beans>

xml配置了A 和B 都是自动装配模型为bytype讲道理要实现autowireMode=2

A.java
public class A {

}

B.java
public class B {

}

提供一个后置处理器来获取A的自动装配模型
ZiluBeanFactoryPostprocessor.java
@Component
public class ZiluBeanFactoryPostprocessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        GenericBeanDefinition a = (GenericBeanDefinition)
                beanFactory.getBeanDefinition("a");
        //打印A 的注入模型
        System.out.println("a mode="+a.getAutowireMode());

    }
}

讲道理由于是bytype所以应该打印出来2; 结果如图:

如果笔者把注入模型改成byname则结果应该会改变

接下来笔者验证一个通过注解配置的类加上@Autowried后的注入模型的值

可以看到结果为0,说明这个A类不是自动装配,其实这已经能证明@Autowried不是自动装配了,但是还有更直接的证据证明他不是自动装配,就是通过spring源码当中处理@Autowried的代码可以看出,首先我们写一个bytype的例子看看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">
        <!--自动装配-->
        <bean id="a" class="com.luban.app.A">
        </bean>
        <bean id="b"  class="com.luban.app.B">
        </bean>
</beans>

A.java

public class A {

    B b;

    /**
     * 如果是自动装配需要提供setter
     * 或者提供构造方法
     */
    public void setB(B b) {
        this.b = b;
    }
}

B.java
public class B {

}

上面代码运行起来,调试spring源码当中的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean方法,这个方法主要就是完成属性填充的,也就是大家说的注入

可以看上图1399行有一个判断,判断当前类的注入模式是否bynane或者bytype如果是其中一种则会进入1401行代码执行自动装配的逻辑;因为当前代码我在xml当中配置了自动注入模型为bytype所以这里一定会进入,从上图debug的结果我们可以得知确实也进入了1401行,那我们再看看@Autowried到底是否是一样的呢?

好吧作为良心笔者特意录了一个gif

从上面那个笔者良心录制的gif可以看到当我们使用@Autowired注解去注入一个属性的时候spring在完成属性注入的过程中和自动注入(byname、bytype)的过程不同,spring注解跳过了那个判断,因为不成立,而是用后面的代码去完成属性注入;这也是能说明@Autowired不是自动装配的证据、更是直接打脸@Autowired是先bytype的这种说法;当然除了这个证据还有更加直接的证据,先看代码:

@Component
public class A {
    B b;
    public  A(B b){
        this.b=b;
        System.out.println(b);
        System.out.println("这个b能正常打印,那这算不算自动装配呢?");
        System.out.println("看起来像是constructor这种自动装配模型");
        System.out.println("但是实际呢?我们通过源码来说明");
        System.out.println("这个构造方法没有加任何注解");
        System.out.println("这里主要来说明,一个注解类是不是自动装配");

    }
}

说明一下这个A类的构造方法注入的B是可以注入的,这样算不算注解类的自动注入呢?看起来像,其实本质上他用的也是自动注入的代码实现的,但是笔者还是认为他不是;为什么呢?我们先来分析一下这个b能被注入的原因是什么,同样给一个gif来说明:

其实最关键的就是这行代码:

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也不报错,但是也不完成注入,让这个属性等于null,比如你有个接口I,提供两个实现I1和I2都存在容器当中,然后在A类当中去注入I,并且指定自动注入模型为bytype那么这个时候会找到两个符合条件的bean,spring就迷茫了,注入哪个呢?spring哪个都不注入直接让这个属性为null而且也不出异常;但是如果找到了一个那么注入的时候会调用setter,如果没有提供setter就不会注入;

其次@Autowried是一个注解,加在属性上面spring,

spring会首先根据属性的类型去容器中找,如果没有找到在根据属性的名字找,找到了则注入,没有找到则异常,下图结果就是容器当中没有一个符合的类型和名字都不符合的则异常;

如果先根据类型找到了一个,那么直接注入,下图就是只有一个符合要求的类型能够完美注入;

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

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

以后如果再听到@Autowried是bytype请你纠正他,bytype是一种自动注入模型;@Autowried是一个注解,两个人没有关系,一点关系都没有;@Autowried讲道理算是手动装配;那么一个注解的类到底能不能开启自动装配呢?答案是可以的,但是需要你对spring比较精通,以后笔者再更新;

本文最早更新在我的博客上面,现在都会同步在头条号等自媒体平台上。转载请注明出处,欢迎各位关注!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335