spring自动注入与手动注入得区别

一、手动注入

了解spring得同学都知道,在早期得版本spring是通过xml方式配置得,我们通常往bean中注入一个属性要么提供<property/>标签通过set方法完成注入要么提供<constructor-arg/>标签通过构造方法注入,这种显示得指定我们需要注入得属性叫做手动注入

二、自动注入

我们只需设置bean得注入方式并提供对应得set方法或者构造方法,spring就会自己分析方法完成注入,这就是我们常说的自动注入,但要注意得是我们经常使用得@Autowired注解或者@Resource注解,这个不是自动注入而是手动注入,这个我们会在接下来得案列中进行验证。

spring官方提供了4中自动注入得模式:

ModeExplanation
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方法、构造方法或者属性反射设置属性的值

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值