原创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名称