一、手动注入
了解spring得同学都知道,在早期得版本spring是通过xml方式配置得,我们通常往bean中注入一个属性要么提供<property/>标签通过set方法完成注入要么提供<constructor-arg/>标签通过构造方法注入,这种显示得指定我们需要注入得属性叫做手动注入
二、自动注入
我们只需设置bean得注入方式并提供对应得set方法或者构造方法,spring就会自己分析方法完成注入,这就是我们常说的自动注入,但要注意得是我们经常使用得@Autowired注解或者@Resource注解,这个不是自动注入而是手动注入,这个我们会在接下来得案列中进行验证。
spring官方提供了4中自动注入得模式:
Mode | Explanation |
---|---|
no 0 | (默认)不自动装配。 |
byName 1 | 按属性名称自动装配。Spring 寻找与需要自动装配的属性同名的 bean。例如,如果一个 bean 定义被设置为按名称自动装配并且它包含一个master 属性(即它有一个 setMaster(..) 方法),那么 Spring 会查找一个命名为masterbean,并使用它来设置该属性。 |
byType 2 | 如果容器中恰好存在一个属性类型的 bean,则让属性自动装配。如果存在多个,则会抛出一个致命异常,这表明您可能不会byType 对该 bean 使用自动装配。如果没有匹配的 bean,则不会发生任何事情(未设置属性)。 |
constructor 3 | 类似于byType 但适用于构造函数参数。如果容器中没有一个构造函数参数类型的 bean,则会引发致命错误。 |
通过如下代码当我们在F这个bean中注入属性e时,最终通过获取beanDefinition得注入模型可以看到是0,0就是上面为no得类型,可以看到spring认为这种不属于自动装配得类型。
@Component
public class F {
@Autowired
private E e;
}
@org.junit.Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.autowired");
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) context.getBeanDefinition("f");
System.out.println(beanDefinition.getAutowireMode());
}
//输出注入模型
输出结果: 0
那@Autowired是如何注入得呢,了解spring源码得应该知道,spring首先是先通过属性得类型获取到所有这个类型得beanName,在获取完成后会在内部简历一个beanName和class或者object得映射关系,主要是因为根据类型可能找出多个bean。当找出有多个bean时,会再次根据内部建立得map判断是否有@Primary注解是否有@Priority注解排序优先级,若都没有会通过注入得属性名字匹配出合适得哪一个,若没有则会报错。最终根据得出得bean再通过反射设置(feid.set())完成属性注入,所以这个也是我们显示得声明,其实也是手动注入。
那么自动注入得逻辑是什么呢?
自动注入分为by_constructor,by_type,by_name,构造函数自动注入得逻辑很复杂,需要结合构造函数推断来讲,暂时这块就不讨论,我们主要分析by_type和by_name。
当我们通过beanDefinition将它得注入模型设置为by_type和by_name时
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME); 此时bean得注入模型就变为自动注入了。
spring自动注入得核心代码
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; }
无论是byName还是byType,spring都是利用了java得内省机制,内省机制可以去网上找一篇文章了解一下,和反射有点类似,简单来说就是找到类中得set方法,spring整合了一下内省机制,这个set方法只能是一个引用类型得参数,将set方法提取出来,set后面得name就是需要注入得属性名
入口就是这行代码 ,
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); 只不过byType和byName得区别在于:
byName会先根据这个属性名在beanDefinitionMap中是否存在,这个name必须和bena得name相同,若不存在就不注入,不会报错;@Resouce也是会先根据属性名找判断是否在beanDefinitionMap存在,但如果找不到会在根据type注入。
byType就和@Autowired得注入逻辑有些类似,都是先通过类型找出所有得Name,再根据name去找bean,但是与@Autowired不同得是,若找出多个@Autowired还会根据名字去匹配,但是byType会直接报错。
综上:无论是自动注入还是手动注入,其实本质都是通过set方法、构造方法或者属性反射设置属性的值