【原创】001 | 搭上SpringBoot自动注入源码分析专车
前言
如果这是你第二次看到师长的文章,说明你在觊觎我的美色!O(∩_∩)O哈哈~
点赞+关注再看,养成习惯
没别的意思,就是需要你的窥屏^_^
本系列为SpringBoot深度源码专车系列,第一篇发车!
专车介绍
该趟专车是开往Spring Boot自动注入原理源码分析的专车
专车问题
- Spring Boot何时注入@Autowired标注的属性?
- 如果注入类型的Bean存在多个Spring Boot是如何处理的?
专车示例
- 定义接口
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);
    }
}
以上示例代码很简单,创建了一个接口,接口有两个实现类,然后在控制器中注入实现类,从而完成业务方法的调用。接下来我们就开始对源码进行分析
专车分析
在分析代码之前我们先回忆一下操作对象的步骤:
- 首先我们会实例化一个对象
- 然后调用对象的set方法来设置对象的属性
有了上面的基础知识,接下来就开始揭秘旅程
寻找入口
在分析源码的时候最关键的一步就是寻找程序的入口,有了入口我们就成功了一半,那么如何寻找程序的入口?针对此处的源码分析,我们可以在TestController类上打一个断点,然后查看调用链
 
 基于调用链路,我们看到有一个doCreateBean方法,该方法就是用来创建bean的,也就是我们上面提到的实例化对象部分
实例化Bean
AbstractAutowireCapableBeanFactory#doCreateBean
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);
    }
}
处理属性
AutowiredAnnotationBeanPostProcessor#postProcessProperties
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;
}
注入属性 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
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<String> autowiredBeanNames = new LinkedHashSet<>(1);
        Assert.state(beanFactory != null, "No BeanFactory available");
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {
            // 解析属性依赖
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
        }
        synchronized (this) {
            if (!this.cached) {
                if (value != null || this.required) {
                    this.cachedFieldValue = desc;
                    registerDependentBeans(beanName, autowiredBeanNames);
                    if (autowiredBeanNames.size() == 1) {
                        String autowiredBeanName = autowiredBeanNames.iterator().next();
                        if (beanFactory.containsBean(autowiredBeanName) &&
                                beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                            this.cachedFieldValue = new ShortcutDependencyDescriptor(
                                    desc, autowiredBeanName, field.getType());
                        }
                    }
                }
                else {
                    this.cachedFieldValue = null;
                }
                this.cached = true;
            }
        }
    }
    if (value != null) {
        ReflectionUtils.makeAccessible(field);
        // 给属性设置值,完成注入功能
        field.set(bean, value);
    }
}
解析属性依赖 DefaultListableBeanFactory#resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    if (Optional.class == descriptor.getDependencyType()) {
        return createOptionalDependency(descriptor, requestingBeanName);
    }
    else if (ObjectFactory.class == descriptor.getDependencyType() ||
            ObjectProvider.class == descriptor.getDependencyType()) {
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }
    else {
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
                descriptor, requestingBeanName);
        if (result == null) {
            // 解析依赖
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        return result;
    }
}
解析属性依赖 DefaultListableBeanFactory#doResolveDependency
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        // ...省略代码
        
        // 解析多个Bean,比如Array、List、Map类型,有兴趣可以自己查看分析
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }
        
        // 根据类型获取候选对象,针对studentService而言,该属性的类型为PersonService
        // PersonService有2个实现类,StudentServiceImpl和TeacherServiceImpl
        // 所以此处获取结果为StudentServiceImpl对象和TeacherServiceImpl对象
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        if (matchingBeans.isEmpty()) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            return null;
        }
        String autowiredBeanName;
        Object instanceCandidate;
        // 重点处理,如果存在多个匹配的bean
        if (matchingBeans.size() > 1) {
            // 从已经匹配的bean中选择一个符合的bean
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            if (autowiredBeanName == null) {
                // 如果bean必须注入或者存在多个匹配的bean,则抛出异常
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                }
                else {
                    // In case of an optional Collection/Map, silently ignore a non-unique case:
                    // possibly it was meant to be an empty collection of multiple regular beans
                    // (before 4.3 in particular when we didn't even look for collection beans).
                    return null;
                }
            }
            // 根据bean名称获取对应的示例
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        else {
            // We have exactly one match.
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }
        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(autowiredBeanName);
        }
        if (instanceCandidate instanceof Class) {
            instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
        }
        Object result = instanceCandidate;
        if (result instanceof NullBean) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            result = null;
        }
        if (!ClassUtils.isAssignableValue(type, result)) {
            throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
        }
        // 返回对应的示例对象
        return result;
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}
此处主要根据类型获取所有匹配的bean,如果匹配的bean有多个,那么最后会选择一个符合条件的bean名称,然后将对应的bena实例返回,调用set方法进行进行注入,到此注入的原理本该结束了。但是还是要分析一下Spring Boot是如何选择出符合条件的bean?
选择符合条件的bean DefaultListableBeanFactory#determineAutowireCandidate
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
    Class<?> requiredType = descriptor.getDependencyType();
    // 如果bean对应的primary属性为true,则返回bean对应的名称
    String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
    if (primaryCandidate != null) {
        return primaryCandidate;
    }
    // 如果候选bean使用javax.annotation.Priority标注,返回高优先级bean对应的名称
    String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
    if (priorityCandidate != null) {
        return priorityCandidate;
    }
    // Fallback
    // 如果匹配bean的名称和需要注入的属性名称一致,则返回匹配bean的名称
    for (Map.Entry<String, Object> entry : candidates.entrySet()) {
        String candidateName = entry.getKey();
        Object beanInstance = entry.getValue();
        if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
                matchesBeanName(candidateName, descriptor.getDependencyName())) {
            return candidateName;
        }
    }
    return null;
}
获取符合条件bean名称总结:
- 依据Bean的primary属性
- 依据javax.annotation.Priority
- 依据注入属性的名称
专车总结
- Bean实例化完成后,填充Bean
- 调用AutowiredAnnotationBeanPostProcessor#postProcessProperties处理属性
- 获取所有需要注入的属性
- 根据注入属性的类型从IOC容器中查找匹配实例
- 如果匹配实例存在多个,根据primary属性--->javax.annotation.Priority注解--->注入属性名称依次过滤,返回符合条件的Bean名称
- 过滤之后,存在一个符合条件的Bean名称,则返回对应的实例,否则抛出异常
专车回顾
回顾一下开头的2个问题:
- Spring Boot何时注入@Autowired标注的属性?
- 如果注入类型的Bean存在多个Spring Boot是如何处理的?
第一个问题:是在Bean实例化后,填充Bean的时候注入@Autowired标注的属性
第二个问题:如果存在多个类型的Bean,会根据primary--->javax.annotation.Priority--->名称依次过滤,得到最终匹配的bean名称
 关注公众号
关注公众号
					低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 
							
								
								    上一篇
								      《程序人生》十年风雨-从大学到技术专家我做了啥?你知道的越多,你不知道的越多 点赞再看,养成习惯 本文 GitHub https://github.com/JavaFamily 上已经收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。 前言 你们都知道的,帅丙我本身肯定是达不到技术专家的地步的。 呸,敖丙你个渣男,又标题党 ! 我不是但是我身边很多人是呀,字节跳动,PDD,阿里等等的大佬我认识很多,所以以下是我问了他们的成长路径的总结,还是具有一定的代表性。 身边这些朋友都是在互联网领域多年的大牛了,因为生活和个人习惯的原因,很多都没有写博客的习惯,或者没有公开出来,但是他们却遇到了帅丙,我骚啊,我可以帮他们整理出来啊。 目的是为了让很多跟我一样的新人,对一条完整的职业规划之路有一个清晰的认知,青铜到王者要经历些什么? 青铜-万恶之源 《计算机基础》,这是所有读者大学最开始都会上的课吧,我问了群里的仔,他们都说是的,我想大家也是。 在计算机基础中我们会学到计算机的历史、计算机的特点、进制转换、内存管理、线性数据结构、网络请求协议等等。 计算机基础真心很重要,无比... 
- 
							
								
								    下一篇
								      probie 插件更新,新增实时编程新增了实时编程,使得编程更有趣,更方便 probie 介绍 菜鸟翻译是我从事开发者多年一直想要的一款工具,他可以让英语差的开发者也能写出标准的代码,并且可以看懂英文注释! 效果展示 安装教程 jetbrains 系类 都可以在插件市场 搜索 probie 下载 使用教程 默认快捷键 alt p 右键 probie translate Tools -> 实时编程 默认打开 
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 面试大杂烩
- Red5直播服务器,属于Java语言的直播服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- MySQL表碎片整理

 
			
 
				 
				 
				 
				 
				 
				 
				



 微信收款码
微信收款码 支付宝收款码
支付宝收款码