Java 基础之Autowired 是否是自动注入

相信很多人对Autowired 注解理解不深入,或者是认为此注解就是spring的自动注入。相信看完本篇文章,你会有更加不一样的理解。

首先我们先看下什么是手动注入?在我们的spring应用程序中,定义多个类,其中某些类依赖某些类,xml中要描述类与类之间的依赖关系,这种由程序员定义,并且描述好依赖关系的用法,我们称之为手动注入。我们看个例子:

package com.shadow.data;

public class X {
    private Y y;

    public void setY(Y y) {
        System.out.println("hello set method ...");
        this.y = y;
    }
}
package com.shadow.data;

public class Y {

}
<?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="x" class="com.shadow.data.X">
        <property name="y" ref="y"></property>
    </bean>
    <bean id="y" class="com.shadow.data.Y"></bean>
</beans>

上面我们定义了两个类,X 依赖于 Y 类,并且我们在xml 中定义了他们的依赖关系,当我们启动spring 应用程序时候,会发现有如下打印:

hello set method ...

Process finished with exit code 0

DI(依赖注入)一共有两种主要的方式,分别是基于构造方法的依赖注入和基于setter方法的依赖注入,不管是手动装配还是自动装配都是基于这两种方式来的。@Autowired这种注入方式是上述setter方式的变体,基于反射技术,实现属性注入。

此处,需要注意的是,如果去掉X中的Y属性,打印是相同的。

spring官网有说明自动装配有四种模型分表是no、bytype、byname、constructor。由于Autowired注解首先根据类型注入,所以容易让程序员认为Autowired注解也是自动注入。其实他们不是一回事。

先给出结论,此处借用大神的一段话:依赖注入是一个过程,主要通过setter和构造方法以及一些变体的方式完成把对象依赖、或者填充上的这个过程叫做依赖注入,不管手动装配还是自动装配都有这个过程;而自动装配模型是一种完成自动装配依赖的手段体现,每一种模型都使用了不同的技术去查找和填充bean;而从spring官网上面可以看到spring只提出了4中自动装配模型(严格意义上是三种、因为第一种是no,表示不使用自动装配、使用),这四个模型分别用一个整形来表示,存在spring的beanDefinition当中,任何一个类默认是no这个装配模型,也就是一个被注解的类默认的装配模型是no也就是手动装配;其中no用0来表示;bytype用2来表示;如果某个类X,假设X的bean对应的beanDefinition当中的autowireMode=2则表示这个类X的自动装配模型为bytype;如果autowireMode=1则表示为byname装配模型。

上面代码基础上增加一个类如下:

package com.shadow.data;

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 MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        GenericBeanDefinition x = (GenericBeanDefinition)configurableListableBeanFactory.getBeanDefinition("x");
        System.out.println(x.getAutowireMode());
    }
}

可以看到打印如下:

...
2
hello set method ...

Process finished with exit code 0

如果将xml去掉,每个类上面加Component注解,如下:

@Configuration
@ComponentScan(basePackages = "com.shadow.data")
public class Main {
    public static void main(String[] args) {
        System.out.println("...");
//        ClassPathXmlApplicationContext classPathXmlApplicationContext =
//                new ClassPathXmlApplicationContext("application.xml");
    AnnotationConfigApplicationContext annotationConfigApplicationContext=
            new AnnotationConfigApplicationContext(Main.class);

    }
}

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        GenericBeanDefinition x = (GenericBeanDefinition)configurableListableBeanFactory.getBeanDefinition("x");
        System.out.println(x.getAutowireMode());
    }
}

@Component
public class X {
    @Autowired
    private Y y;

    public void setY(Y y) {
        System.out.println("hello set method ...");
        this.y = y;
    }
}

@Component
public class Y {

}
...
0

Process finished with exit code 0

打印结果如上所示,可以证明Autowired的bean definition中自动注入模型为0,不属于自动注入。