001 | 搭上SpringBoot自动注入源码分析专车
2021-03-14 16:40
标签:pen lazy nec return 自己 primary alt failed rem 点击上方“java进阶架构师”,选择右上角“置顶公众号” 该趟专车是开往Spring Boot自动注入原理源码分析的专车 如果注入类型的Bean存在多个Spring Boot是如何处理的? 定义接口 定义接口的一个实现 定义接口的另一个实现 定义控制器 以上示例代码很简单,创建了一个接口,接口有两个实现类,然后在控制器中注入实现类,从而完成业务方法的调用。接下来我们就开始对源码进行分析 在分析代码之前我们先回忆一下操作对象的步骤: 在分析源码的时候最关键的一步就是寻找程序的入口,有了入口我们就成功了一半,那么如何寻找程序的入口?针对此处的源码分析,我们可以在TestController类上打一个断点,然后查看调用链 基于调用链路,我们看到有一个doCreateBean方法,该方法就是用来创建bean的,也就是我们上面提到的实例化对象部分 AbstractAutowireCapableBeanFactory#doCreateBean AutowiredAnnotationBeanPostProcessor#postProcessProperties 注入属性 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject 解析属性依赖 DefaultListableBeanFactory#resolveDependency 解析属性依赖 DefaultListableBeanFactory#doResolveDependency 此处主要根据类型获取所有匹配的bean,如果匹配的bean有多个,那么最后会选择一个符合条件的bean名称,然后将对应的bena实例返回,调用set方法进行进行注入,到此注入的原理本该结束了。但是还是要分析一下Spring Boot是如何选择出符合条件的bean? 选择符合条件的bean DefaultListableBeanFactory#determineAutowireCandidate 获取符合条件bean名称总结: 依据注入属性的名称 回顾一下开头的2个问题: 第二个问题:如果存在多个类型的Bean,会根据primary--->javax.annotation.Priority--->名称依次过滤,得到最终匹配的bean名称 ———— e n d ———— 001 | 搭上SpringBoot自动注入源码分析专车 标签:pen lazy nec return 自己 primary alt failed rem 原文地址:https://blog.51cto.com/15009303/2553017
20大进阶架构专题每日送达
本系列为SpringBoot深度源码专车系列,第一篇发车!专车介绍
专车问题
专车示例
public interface PersonService {
String hello(String name);
}
@Service(value = "studentService")
public class StudentServiceImpl implements PersonService {
@Override
public String hello(String name) {
return "[student service] hello " + name;
}
}
@Service(value = "teacherService")
public class TeacherServiceImpl implements PersonService {
@Override
public String hello(String name) {
return "[teacher service] hello " + name;
}
}
@RestController
public class TestController {
@Autowired
private PersonService studentService;
@Autowired
private PersonService teacherService;
@GetMapping("/hello")
public String hello(@RequestParam(name = "name") String name) {
return studentService.hello(name) + "=======>" + teacherService.hello(name);
}
}
专车分析
寻找入口
实例化Bean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class> beanType = instanceWrapper.getWrappedClass();
// ...省略部分代码
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 填充bean,也就是我们上面提到的调用对象的set方法设置对象属性
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// ...省略部分代码
return exposedObject;
}
填充bean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// ...省略代码
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 遍历所有的后置处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 通过断点分析我们可以得知此处调用的是AutowiredAnnotationBeanPostProcessor#postProcessProperties
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
处理属性
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 查找当前bean需要注入的元数据信息,以TestController为例,那么需要注入的就是studentService和teacherService两个属性
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 注入属性
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 获取属性,此处的属性就是studentService
Field field = (Field) this.member;
// 属性对应的value
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set
protected String determineAutowireCandidate(Map
专车总结
专车回顾
第一个问题:是在Bean实例化后,填充Bean的时候注入@Autowired标注的属性
微服务、高并发、JVM调优、面试专栏等20大进阶架构师专题请关注公众号【Java进阶架构师】后在菜单栏查看。
看到这里,说明你喜欢本文
你的转发,是对我最大的鼓励!在看亦是支持
下一篇:5、Spring Boot缓存
文章标题:001 | 搭上SpringBoot自动注入源码分析专车
文章链接:http://soscw.com/index.php/essay/64629.html