@Autowired浅析

@Autowired浅析

首先放几段代码和几个问题,带着思考去看接下来的结论

第一个问题

第一段代码:容器初始化完毕,控制台是否会打印(“This is a method from TeachService”)这句话?

@Service
public class StudyService {


	public void setTeacherService(TeachService teacherService){
		teacherService.teach();
	}

}


@Service
public class TeachService {

	public void teach(){
		System.out.println("This is a method from TeachService");
	}


}

答案是会,但是这里我是做了一个细节上的配置,正常情况下,即默认情况是不会打印的,稍后细说。

在这里插入图片描述

第二个问题

说起@Autowired注解,大家想到的就是byType,那么看下面的代码。

//声明一个接口
public interface People {
	void showIdentity();
}
//写两个实现类,都注入到spring容器中
@Service
public class StudyService implements People {
	@Override
	public void showIdentity() {
		System.out.println("I am a student");
	}
}

@Service
public class TeachService implements People {
	@Override
	public void showIdentity() {
		System.out.println("I am a teacher");
	}
}
//使用另外的bean注入People类型,请注意,这里注入的类型是接口,变量名使用的是studyService
//如果按照byType的理解,容器初始化时应该会报错,同一个type找到多个bean,不知道注入哪个
@Service
public class Leader {
	@Autowired
	People studyService;
	public void showYourIdentity(){
		studyService.showIdentity();
	}
}

其实呢,看下图运行成果

在这里插入图片描述

第三个问题

读过源码的同学可能了解过populateBean方法里有一段判断逻辑

在这里插入图片描述

这里的逻辑是判断bean的注入类型是否为byName或者byType,看到图中的值,相信大家都知道,是不会进这个if分支的,那么是为什么呢?接下来放一段官网对于注入的一个解释。

在这里插入图片描述

下面是对于上面的一个部分翻译

模式 解释
no 非自动装配,bean的应用需要通过ref元素定义
byName 按属性名称自动装配。Spring容器会寻找与需要自动实现的属性同名的bean。
byType 如果容器中恰好存在该属性类型的一个bean,则允许该属性被自动调用。如果存在多个,就会抛出一个异常,这表明不能对该bean使用byType自动装配。
constructor 类似于byType,但适用于构造函数参数。

问题解答

按照上述官网解释,如果@Autowired注解真的是像大部分网上所说的byType,那么我第二个问题的代码怎么可能运行成功呢?接下来用spring的后置处理器去获取一下StudyService的BeanDefinition对象,通过BeanDefinition对象查看装配类型究竟是什么吧!

@Configuration
public class MyPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		GenericBeanDefinition s = (GenericBeanDefinition) beanFactory.getBeanDefinition("studyService");
		System.out.println("默认装配类型:"+s.getAutowireMode());
	}
}

在这里插入图片描述

由上图可知@Autowired的装配类型为0,即官网所说的NO-非自动装配。

有的人可能疑问了,为什么叫非自动装配?spring明明帮我们把需要的类创建出来了呀,这个问题接下来会解释。

先回顾第一个问题,为什么明明没有使用注解和xml,set方法中的bean依旧注入成功了呢?依旧用到了后置处理器。上代码

@Configuration
public class MyPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		GenericBeanDefinition s = (GenericBeanDefinition) beanFactory.getBeanDefinition("studyService");
        //重点在这里,通过后置处理器得到BeanDefinition对象后,修改autowireMode的值为2,即byType
		s.setAutowireMode(2);
	}
}

在这里插入图片描述

怎么做到的已经展示完了,接下来结合这一和二的内容,给大家做一个简短的解释。

首先大家所理解的自动装配,是以开发人员的角度来说:我是一个开发,spring帮我把TeachService创建并注入到了StudyService中,这个过程中,“我”并没有参与什么,只是声明了一个注解。

这就好比:

​以前我们大家吃饭,需要自己买菜->做饭->吃饭->洗碗,做完整个周期性的任务才算完成;

​现在有了餐馆(spring),我们只需要到餐馆(spring)声明我要吃鱼香肉丝,在(买菜->做饭->吃饭->洗 碗)这个周期中,我们只需做到“吃饭”即可。

请注意,上述描述的角度是我->餐馆的顾客|开发人员->spring的使用者

不知道大家能不能明白我所说的。

接下来的是我个人理解了,可能有所错误,大家可以共同探讨!!!

我理解的自动装配是相对于spring角度,也就是餐馆角度;

当我走进餐馆时(我使用setTeachService方法),老板看到我就“觉得”我想要鱼香肉丝(对应autowiredMode修改为2之后,spring容器发现setTeachService方法时),并没有问我是否真的需要(比如我就是想单纯实现一个setTeachService方法自己用呢,对吧),就直接给我上了一盘鱼香肉丝饭。

简单的来说:在autowiredMode不等于0时,当开发人员提供了一个spring认可的注入方式,即set和construct形式时,spring会直接注入这两种DI形式中的bean(前提是bean)

这里插一个小知识点

官方文档说明了,DI(依赖注入)有两种主要的变体,即基于构造器的依赖注入和基于setter的依赖注入。

即使是常用的@Autowired注解,也是通过反射生成set方法进行的赋值。

在这里插入图片描述

本菜鸟也是刚入行三年,如果上述有什么问题,大家可以留言,我会积极改正和学习的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章