前言

如果这是你第二次看到师长,说明你在觊觎我的美色!

点赞+关注再看,养成习惯

没别的意思,就是需要你的窥屏^_^

本系列为SpringBoot深度源码专车系列,第一篇发车!

专车介绍

该趟专车是开往Spring Boot自动注入原理源码分析的专车

专车问题

Spring Boot何时注入@Autowired标注的属性?如果注入类型的Bean存在多个Spring Boot是如何处理的?

专车示例

定义接口publi直播源码c 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 Pers直播源码onService studentService; @Autowired private PersonService teacherService; @GetMapping(“/hello”) public String hello(@RequestParam(name = “name”) String name) { return studentServi直播源码ce.hello(name) + “=======>” + teacherService.hello(name); } }

以上示例代码很简单,创建了一个接口,接口有两个实现类,然后在控制器中注入实现类,从而完成业务方法的调用。接下来我们就开始对源码进行分析

专车分析

在分析代码之前我们先回忆一下操作对象的步骤:

首先我们会实例化一个对象然后调用对象的set方法来设置对象的属性

有了上面的基直播源码础知识,接下来就开始揭秘旅程

寻找入口

在分析源码的时候最关键的一步就是寻找程序的入口,有了入口我们就成功了一半,那么如何寻找程序的入口?针对此处的源码分析,我们可以在TestController类上打一个断点,然后查看调用链

基于调用链路,我们看到有一个doCreateBean方法,该方法就是用来创建bean的,也就是我们上面提到的实例化对象部分

实例化Bean

AbstractAutowireCapab直播源码leBeanFactory#doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the be直播源码an. 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 = init直播源码ializeBean(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 (filter直播源码edPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), bean直播源码Name); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } } if (needsDepCheck) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForD直播源码ependencyCheck(bw, mbd.allowCaching); } checkDependencies(beanName, mbd, filteredPds, pvs); } if (pvs != null) { applyPropertyValues(beanName, mbd, bw, pvs); } }

处理属性

Autowir直播源码edAnnotationBeanPostProcessor#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); } cat直播源码ch (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.s直播源码tate(beanFactory != null, “No BeanFactory available”); TypeConverter typeConverter = beanFactory.getTypeConverter(); try { // 解析属性依赖 value = beanFactory.resolveDependency(desc, beanNam直播源码e, 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())) { thi直播源码s.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 Ob直播源码ject 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, requestingBeanNam直播源码e); } else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { return new DependencyObjectProvider(descriptor, reques直播源码tingBeanName); } else if (javaxInjectProviderClass == descriptor.getDependencyType()) { return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName); } else 直播源码{ Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) { // 解析依赖 result = doResolveDependency(desc直播源码riptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } }

解析属性依赖

DefaultListableBeanFactory#doResolveDependency public Object doResolveDependency(DependencyDesc直播源码riptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = C直播源码onstructorResolver.setCurrentInjectionPoint(descriptor); try { // …省略代码 // 解析多个Bean,比如Array、List、Map类型,有兴趣可以自己查看分析 Object multipleBeans = resolveMultipleBeans(descriptor, beanName, 直播源码autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // 根据类型获取候选对象,针对studentService而言,该属性的类型为PersonService // PersonService有2个实现类,StudentServic直播源码eImpl和TeacherServiceImpl // 所以此处获取结果为StudentServiceImpl对象和TeacherServiceImpl对象 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isE直播源码mpty()) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instan直播源码ceCandidate; // 重点处理,如果存在多个匹配的bean if (matchingBeans.size() > 1) { // 从已经匹配的bean中选择一个符合的bean autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowire直播源码dBeanName == null) { // 如果bean必须注入或者存在多个匹配的bean,则抛出异常 if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(descriptor.getResolvableType(), matc直播源码hingBeans); } 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 // (b直播源码efore 4.3 in particular when we didnt 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(autow直播源码iredBeanName, type, this); } Object result = instanceCandidate; if (result instanceof NullBean) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolva直播源码bleType(), descriptor); } result = null; } if (!ClassUtils.isAssignableValue(type, result)) { throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.ge直播源码tClass()); } // 返回对应的示例对象 return result; } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } }

此处主要根据类型获取所有匹配的bean,如果匹配的bean有多个,那么最后会选择一个直播源码符合条件的bean名称,然后将对应的bena实例返回,调用set方法进行进行注入,到此注入的原理本该结束了。但是还是要分析一下Spring Boot是如何选择出符合条件的bean?

选择符合条件的bean

DefaultListableBeanFactory#

determineAutowireCandidate protected String determineAutowireCandidate(Ma直播源码p<String, Object> candidates, DependencyDescriptor descriptor) { Class<?> requiredType = descriptor.getDependencyType(); // 如果bean对应的primary属性为true,则返回bean对应的名称 String primaryCandidate = d直播源码eterminePrimaryCandidate(candidates, requiredType); if (primaryCandidate != null) { return primaryCandidate; } // 如果候选bean使用javax.annotation.Priority标注,返回高优先级bean对应的名称 String prior直播源码ityCandidate = 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 && thi直播源码s.resolvableDependencies.containsValue(beanInstance)) || matchesBeanName(candidateName, descriptor.getDependencyName())) { return candidateName; } } return null; }

获取符合条件bean名称总直播源码结:

依据Bean的primary属性依据javax.annotation.Priority依据注入属性的名称

专车总结

Bean实例化完成后,填充Bean调用AutowiredAnnotationBeanPostProcessor#postProcessProperties处理属性获取所有需要注入的属性根据注入属性的类型从IOC容器中查找匹配实例如果匹配实例存在多个,根据primary属性—>ja直播源码vax.annotation.Priority注解—>注入属性名称依次过滤,返回符合条件的Bean名称过滤之后,存在一个符合条件的Bean名称,则返回对应的实例,否则抛出异常

专车回顾

回顾一下开头的2个问题:

Spring Boot何时注入@Autowired标注的属性?如果注入类型的Bean存在多个Spring Boot是如何处理的?

第一个问题:是在Bean实例化后,填充Bean的时候注入@Au直播源码towired标注的属性

第二个问题:如果存在多个类型的Bean,会根据primary—>

javax.annotation.Priority—>名称依次过滤,得到最终匹配的bean名称

最后

师长,【java进阶架构师】号主,短短一年在各大平台斩获15W+程序员关注,专注分享Java进阶、架构技术、高并发、微服务、BAT面试、redis专题、JVM调优、Springboot源码、mysql优化等直播源码20大进阶架构专题。

作者 nasiapp

在线客服
官方客服
我们将24小时内回复。
12:01
您好,有任何疑问请与我们联系!

选择聊天工具: