本系列文章:html
读源码,咱们能够从第一行读起java
推荐阅读:spring
Spring杂谈缓存
本系列文章将会带你一行行的将Spring的源码吃透,推荐阅读的文章是阅读源码的基础!app
在开始探讨源码前,咱们先思考两个问题:编辑器
经过new关键字,反射,克隆等手段建立出来的就是对象。在Spring中,Bean必定是一个对象,可是对象不必定是一个Bean,一个被建立出来的对象要变成一个Bean要通过不少复杂的工序,例如须要被咱们的
BeanPostProcessor
处理,须要通过初始化,须要通过AOP
(AOP
自己也是由后置处理器完成的)等。ide
咱们仍是回到流程图中,其中相关的步骤以下:
在前面的三篇文章中,咱们已经分析到了第3-5
步的源码,而若是你对Spring源码稍有了解的话,就是知道建立对象以及将对象变成一个Bean的过程发生在第3-11
步骤中。中间的五步分别作了什么呢?
就像名字所说的那样,注册BeanPostProcessor
,这段代码在Spring官网阅读(八)容器的扩展点(三)(BeanPostProcessor)已经分析过了,因此在本文就直接跳过了,若是你没有看过以前的文章也没有关系,你只须要知道,在这里Spring将全部的BeanPostProcessor
注册到了容器中
初始化容器中的messageSource
,若是程序员没有提供,默认会建立一个org.springframework.context.support.DelegatingMessageSource
,Spring官网阅读(十一)ApplicationContext详细介绍(上) 已经介绍过了。
初始化事件分发器,若是程序员没有提供,那么默认建立一个org.springframework.context.event.ApplicationEventMulticaster
,Spring官网阅读(十二)ApplicationContext详解(中)已经作过详细分析,再也不赘述
留给子类复写扩展使用
注册事件监听器,就是将容器中全部实现了org.springframework.context.ApplicationListener
接口的对象放入到监听器的集合中。
在完成了上面的一些准备工做后,Spring开始来建立Bean了,按照流程,首先被调用的就是
finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)
方法,咱们就以这个方法为入口,一步步跟踪源码,看看Spring中的Bean究竟是怎么建立出来的,固然,本文主要关注的是建立对象的这个过程,对象变成Bean的流程咱们在后续文章中再分析
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // 初始化一个ConversionService用于类型转换,这个ConversionService会在实例化对象的时候用到 if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // 添加一个StringValueResolver,用于处理占位符,能够看到,默认状况下就是使用环境中的属性值来替代占位符中的属性 if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // 建立全部的LoadTimeWeaverAware String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // 静态织入完成后将临时的类加载器设置为null,因此除了建立LoadTimeWeaverAware时可能会用到临时类加载器,其他状况下都为空 beanFactory.setTempClassLoader(null); // 将全部的配置信息冻结 beanFactory.freezeConfiguration(); // 开始进行真正的建立 beanFactory.preInstantiateSingletons(); }
上面的方法最终调用了org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
来建立Bean。
其源码以下:
public void preInstantiateSingletons() throws BeansException { // 全部bd的名称 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // 遍历全部bd,一个个进行建立 for (String beanName : beanNames) { // 获取到指定名称对应的bd RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 对不是延迟加载的单例的Bean进行建立 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 判断是不是一个FactoryBean if (isFactoryBean(beanName)) { // 若是是一个factoryBean的话,先建立这个factoryBean,建立factoryBean时,须要在beanName前面拼接一个&符号 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { // 判断是不是一个SmartFactoryBean,而且不是懒加载的,就意味着,在建立了这个factoryBean以后要立马调用它的getObject方法建立另一个Bean isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { // 不是factoryBean的话,咱们直接建立就好了 getBean(beanName); } } } // 在建立了全部的Bean以后,遍历 for (String beanName : beanNames) { // 这一步实际上是从缓存中获取对应的建立的Bean,这里获取到的一定是单例的 Object singletonInstance = getSingleton(beanName); // 判断是不是一个SmartInitializingSingleton,最典型的就是咱们以前分析过的EventListenerMethodProcessor,在这一步完成了对已经建立好的Bean的解析,会判断其方法上是否有 @EventListener注解,会将这个注解标注的方法经过EventListenerFactory转换成一个事件监听器并添加到监听器的集合中 if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
上面这段代码总体来讲应该不难,不过它涉及到了一个点就是factoryBean
,若是你对它不够了解的话,请参考我以前的一篇文章:Spring官网阅读(七)容器的扩展点(二)FactoryBean
从上面的代码分析中咱们能够知道,Spring最终都会调用到getBean
方法,而getBean
并非真正干活的,doGetBean
才是。另外doGetBean
能够分为两种状况
FactoryBean
,此时实际传入的name = & + beanName
name = beanName
其代码以下:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 前面咱们说过了,传入的name可能时& + beanName这种形式,这里作的就是去除掉&,获得beanName final String beanName = transformedBeanName(name); Object bean; // 这个方法就很牛逼了,经过它解决了循环依赖的问题,不过目前咱们只须要知道它是从单例池中获取已经建立的Bean便可,循环依赖后面我单独写一篇文章 // 方法做用:已经建立的Bean会被放到单例池中,这里就是从单例池中获取 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // 若是直接从单例池中获取到了这个bean(sharedInstance),咱们能直接返回吗? // 固然不能,由于获取到的Bean多是一个factoryBean,若是咱们传入的name是 & + beanName 这种形式的话,那是能够返回的,可是咱们传入的更多是一个beanName,那么这个时候Spring就还须要调用这个sharedInstance的getObject方法来建立真正被须要的Bean bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // 在缓存中获取不到这个Bean // 原型下的循环依赖直接报错 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 核心要义,找不到咱们就从父容器中再找一次 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } // 若是不只仅是为了类型推断,也就是表明咱们要对进行实例化 // 那么就将bean标记为正在建立中,其实就是将这个beanName放入到alreadyCreated这个set集合中 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 检查合并后的bd是不是abstract,这个检查如今已经没有做用了,一定会经过 checkMergedBeanDefinition(mbd, beanName, args); // @DependsOn注解标注的当前这个Bean所依赖的bean名称的集合,就是说在建立当前这个Bean前,必需要先将其依赖的Bean先完成建立 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { // 遍历全部申明的依赖 for (String dep : dependsOn) { // 若是这个bean所依赖的bean又依赖了当前这个bean,出现了循环依赖,直接报错 if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // 注册bean跟其依赖的依赖关系,key为依赖,value为依赖所从属的bean registerDependentBean(dep, beanName); try { // 先建立其依赖的Bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 咱们目前只分析单例的建立,单例看懂了,原型天然就懂了 if (mbd.isSingleton()) { // 这里再次调用了getSingleton方法,这里跟方法开头调用的getSingleton的区别在于,这个方法多传入了一个ObjectFactory类型的参数,这个ObjectFactory会返回一个Bean sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // 省略原型跟域对象的相关代码 return (T) bean; }
配合注释看这段代码应该也不难吧,咱们重点关注最后在调用的这段方法便可
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { // 从单例池中获取,这个地方确定也获取不到 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 工厂已经在销毁阶段了,这个时候还在建立Bean的话,就直接抛出异常 if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } // 在单例建立前,记录一下正在建立的单例的名称,就是把beanName放入到singletonsCurrentlyInCreation这个set集合中去 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 这里调用了singletonFactory的getObject方法,对应的实现就是在doGetBean中的那一段lambda表达式 singletonObject = singletonFactory.getObject(); newSingleton = true; } // 省略异常处理 finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // 在单例完成建立后,将beanName从singletonsCurrentlyInCreation中移除 // 标志着这个单例已经完成了建立 afterSingletonCreation(beanName); } if (newSingleton) { // 添加到单例池中 addSingleton(beanName, singletonObject); } } return singletonObject; } }
分析完上面这段代码,咱们会发现,核心的建立Bean的逻辑就是在singletonFactory.getObject()
这句代码中,而其实现就是在doGetBean
方法中的那一段lambda表达式,以下:
实际就是经过createBean
这个方法建立了一个Bean而后返回,createBean
又干了什么呢?
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; // 解析获得beanClass,为何须要解析呢?若是是从XML中解析出来的标签属性确定是个字符串嘛 // 因此这里须要加载类,获得Class对象 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // 对XML标签中定义的lookUp属性进行预处理,若是只能根据名字找到一个就标记为非重载的,这样在后续就不须要去推断究竟是哪一个方法了,对于@LookUp注解标注的方法是不须要在这里处理的,AutowiredAnnotationBeanPostProcessor会处理这个注解 try { mbdToUse.prepareMethodOverrides(); } // 省略异常处理... try { // 在实例化对象前,会通过后置处理器处理 // 这个后置处理器的提供了一个短路机制,就是能够提早结束整个Bean的生命周期,直接从这里返回一个Bean // 不过咱们通常不会这么作,它的另一个做用就是对AOP提供了支持,在这里会将一些不须要被代理的Bean进行标记,就本文而言,你能够暂时理解它没有起到任何做用 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } // 省略异常处理... try { // doXXX方法,真正干活的方法,doCreateBean,真正建立Bean的方法 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } // 省略异常处理... }
本文只探讨对象是怎么建立的,至于怎么从一个对象变成了Bean,在后面的文章咱们再讨论,因此咱们主要就关注下面这段代码
// 这个方法真正建立了Bean,建立一个Bean会通过 建立对象 > 依赖注入 > 初始化 这三个过程,在这个过程当中,BeanPostPorcessor会穿插执行,本文主要探讨的是建立对象的过程,因此关于依赖注入及初始化咱们暂时省略,在后续的文章中再继续研究 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { // 这行代码看起来就跟factoryBean相关,这是什么意思呢? // 在下文我会经过例子介绍下,你能够暂时理解为,这个地方返回的就是个null instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // 这里真正的建立了对象 instanceWrapper = createBeanInstance(beanName, mbd, args); } // 省略依赖注入,初始化 }
这里我先分析下this.factoryBeanInstanceCache.remove(beanName)
这行代码。这里须要说一句,我写的这个源码分析的系列很是的细节,之因此选择这样一个个扣细节是由于我本身在阅读源码过程当中常常会被这些问题阻塞,那么借着这些文章将本身踩过的坑分享出来能够减小做为读者的你本身在阅读源码时的障碍,其次也可以提高本身阅读源码的能力。若是你对这些细节不感兴趣的话,能够直接跳过,能把握源码的主线便可。言归正传,咱们回到这行代码this.factoryBeanInstanceCache.remove(beanName)
。何时factoryBeanInstanceCache
这个集合中会有值呢?这里我仍是以示例代码来讲明这个问题,示例代码以下:
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class); } } // 没有作什么特殊的配置,就是扫描了须要的组件,测试时换成你本身的包名 @ComponentScan("com.dmz.source.instantiation") @Configuration public class Config { } // 这里申明了一个FactoryBean,而且经过@DependsOn注解申明了这个FactoryBean的建立要在orderService以后,主要目的是为了在DmzFactoryBean建立前让容器发生一次属性注入 @Component @DependsOn("orderService") public class DmzFactoryBean implements FactoryBean<DmzService> { @Override public DmzService getObject() throws Exception { return new DmzService(); } @Override public Class<?> getObjectType() { return DmzService.class; } } // 没有经过注解的方式将它放到容器中,而是经过上面的DmzFactoryBean来管理对应的Bean public class DmzService { } // OrderService中须要注入dmzService @Component public class OrderService { @Autowired DmzService dmzService; }
在这段代码中,由于咱们明确的表示了DmzFactoryBean
是依赖于orderService
的,因此一定会先建立orderService
再建立DmzFactoryBean
,建立orderService
的流程以下:
其中的属性注入阶段,咱们须要细化,也能够画图以下:
为orderService进行属性注入能够分为这么几步
找到须要注入的注入点,也就是orderService中的dmzService字段
根据字段的类型以及名称去容器中查询符合要求的Bean
当遍历到一个FactroyBean时,为了肯定其getObject方法返回的对象的类型须要建立这个FactroyBean(只会到对象级别),而后调用这个建立好的FactroyBean的getObjectType方法明确其类型并与注入点须要的类型比较,看是不是一个候选的Bean,在建立这个FactroyBean时就将其放入了factoryBeanInstanceCache
中。
在肯定了惟一的候选Bean以后,Spring就会对这个Bean进行建立,建立的过程又通过三个步骤
在建立对象时,由于此时factoryBeanInstanceCache
已经缓存了这个Bean对应的对象,因此直接经过this.factoryBeanInstanceCache.remove(beanName)
这行代码就返回了,避免了二次建立对象。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { Class<?> beanClass = resolveBeanClass(mbd, beanName); // 省略异常 // 经过bd中提供的instanceSupplier来获取一个对象 // 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不经常使用 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // bd中提供了factoryMethodName属性,那么要使用工厂方法的方式来建立对象,工厂方法又会区分静态工厂方法跟实例工厂方法 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // 在原型模式下,若是已经建立过一次这个Bean了,那么就不须要再次推断构造函数了 boolean resolved = false; // 是否推断过构造函数 boolean autowireNecessary = false; // 构造函数是否须要进行注入 if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } } // 推断构造函数 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 调用无参构造函数建立对象 return instantiateBean(beanName, mbd); }
上面这段代码在Spring官网阅读(一)容器及实例化 已经分析过了,可是当时咱们没有深究建立对象的细节,因此本文将详细探讨Spring中的这个对象究竟是怎么建立出来的,这也是本文的主题。
在Spring官网阅读(一)容器及实例化 这篇文章中,我画了下面这么一张图
从上图中咱们能够知道Spring在实例化对象的时候有这么几种方式
咱们接下来就一一分析其中的细节:
在Spring官网阅读(一)容器及实例化 文中介绍过这种方式,由于这种方式咱们基本不会使用,并不重要,因此这里就再也不赘述,我这里就直接给出一个使用示例,你们自行体会吧
public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); // 直接注册一个Bean,而且指定它的supplier就是Service::new ac.registerBean("service", Service.class,Service::new,zhe'sh); ac.refresh(); System.out.println(ac.getBean("service")); }
对应代码以下:
protected BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs); }
上面这段代码主要干了两件事
ConstructorResolver
对象,从类名来看,它是一个构造器解析器instantiateUsingFactoryMethod
方法,这个方法见名知意,使用FactoryMethod
来完成实例化基于此,咱们解决一个问题,ConstructorResolver
是什么?
在要研究一个类前,咱们最早应该从哪里入手呢?不少没有经验的同窗可能会闷头看代码,可是实际上最好的学习方式是先阅读类上的javaDoc
ConstructorResolver上的javaDoc以下:
上面这段javaDoc翻译过来就是这个类就是用来解析构造函数跟工厂方法的代理者,而且它是经过参数匹配的方式来进行推断构造方法或者工厂方法。
看到这里不知道小伙伴们是否有疑问,就是明明这个类不只负责推断构造函数,还会负责推断工厂方法,那么为何类名会叫作ConstructorResolver
呢?咱们知道Spring的代码在业界来讲绝对是最规范的,没有之一,这样来讲的话,这个类最合适的名称应该是ConstructorAndFactoryMethodResolver
才对,由于它不只负责推断了构造函数还负责推断了工厂方法嘛!
这里我须要说一下我本身的理解。*对于一个Bean,它是经过构造函数完成实例化的,或者经过工厂方法实例化的,其实在这个Bean看来都没有太大区别,这二者均可以称之为这个Bean的构造器,由于经过它们都能构造出一个Bean。*因此Spring就把二者统称为构造器
了,因此这个类名也就被称为ConstructorResolver
了。
Spring在不少地方体现了这种实现,例如在XML配置的状况下,不论咱们是使用构造函数建立对象仍是使用工厂方法建立对象,其参数的标签都是使用constructor-arg
。好比下面这个例子
<bean id="dmzServiceGetFromStaticMethod" factory-bean="factoryBean" factory-method="getObject"> <constructor-arg type="java.lang.String" value="hello" name="s"/> <constructor-arg type="com.dmz.source.instantiation.service.DmzFactory" ref="factoryBean"/> </bean> <!--测试静态工厂方法建立对象--> <bean id="service" class="com.dmz.official.service.MyFactoryBean" factory-method="staticGet"> <constructor-arg type="java.lang.String" value="hello"/> </bean> <bean id="dmzService" class="com.dmz.source.instantiation.service.DmzService"> <constructor-arg name="s" value="hello"/> </bean>
在对这个类有了大概的了解后,咱们就须要来分析它的源码,这里我就不把它单独拎出来分析了,咱们借着Spring的流程看看这个类干了什么事情
核心目的:推断出要使用的factoryMethod以及调用这个FactoryMethod要使用的参数,而后反射调用这个方法实例化出一个对象
这个方法的代码太长了,因此咱们将它拆分红为一段一段的来分析
在分析上面的代码以前,咱们先来看看这个方法的参数都是什么含义
方法上关于参数的介绍如图所示
beanName
:当前要实例化的Bean的名称mbd
:当前要实例化的Bean对应的BeanDefinitionexplicitArgs
:这个参数在容器启动阶段咱们能够认定它就是null,只有显示的调用了getBean方法,而且传入了明确的参数,例如:getBean("dmzService","hello")
这种状况下才会不为null,咱们分析这个方法的时候就直接认定这个参数为null便可。public BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { // 第一段代码:建立并初始话一个BeanWrapperImpl BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); // ...... }
BeanWrapperImpl是什么呢?若是你看过我以前的文章:Spring官网阅读(十四)Spring中的BeanWrapper及类型转换,那么你对这个类应该不会陌生,它就是对Bean进行了一层包装,而且在建立Bean的时候以及进行属性注入的时候可以进行类型转换。就算你没看过以前的文章也不要紧,只要记住两点
其层级关系以下:
回到咱们的源码分析,咱们先来看看new BeanWrapperImpl()
作了什么事情?
对应代码以下:
// 第一步:调用空参构造 public BeanWrapperImpl() { // 调用另一个构造函数,表示要注册默认的属性编辑器 this(true); } // 这个构造函数代表是否要注册默认编辑器,上面传入的值为true,表示须要注册 public BeanWrapperImpl(boolean registerDefaultEditors) { super(registerDefaultEditors); } // 调用到父类的构造函数,肯定要使用默认的属性编辑器 protected AbstractNestablePropertyAccessor(boolean registerDefaultEditors) { if (registerDefaultEditors) { registerDefaultEditors(); } // 对typeConverterDelegate进行初始化 this.typeConverterDelegate = new TypeConverterDelegate(this); }
总的来讲建立的过程很是简单。第一,肯定要注册默认的属性编辑器;第二,对typeConverterDelegate属性进行初始化。
紧接着,咱们看看在初始化这个BeanWrapper
作了什么?
// 初始化BeanWrapper,主要就是将容器中配置的conversionService赋值到当前这个BeanWrapper上 // 同时注册定制的属性编辑器 protected void initBeanWrapper(BeanWrapper bw) { bw.setConversionService(getConversionService()); registerCustomEditors(bw); }
还记得conversionService
在何时被放到容器中的吗?就是在finishBeanFactoryInitialization的时候啦~!
对conversionService
属性完成赋值后就开始注册定制的属性编辑器,代码以下:
// 传入的参数就是咱们的BeanWrapper,它同时也是一个属性编辑器注册表 protected void registerCustomEditors(PropertyEditorRegistry registry) { PropertyEditorRegistrySupport registrySupport = (registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null); if (registrySupport != null) { // 这个配置的做用就是在注册默认的属性编辑器时,能够增长对数组到字符串的转换功能 // 默认就是经过","来切割字符串转换成数组,对应的属性编辑器就是StringArrayPropertyEditor registrySupport.useConfigValueEditors(); } // 将容器中的属性编辑器注册到当前的这个BeanWrapper if (!this.propertyEditorRegistrars.isEmpty()) { for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) { registrar.registerCustomEditors(registry); // 省略异常处理~ } } // 这里咱们没有添加任何的自定义的属性编辑器,因此确定为空 if (!this.customEditors.isEmpty()) { this.customEditors.forEach((requiredType, editorClass) -> registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass))); } }
public BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { // 省略已经分析的第一段代码,到这里已经获得了一个具备类型转换功能的BeanWrapper // 实例化这个Bean的工厂Bean Object factoryBean; // 工厂Bean的Class Class<?> factoryClass; // 静态工厂方法或者是实例化工厂方法 boolean isStatic; /*下面这段代码就是为上面申明的这三个属性赋值*/ String factoryBeanName = mbd.getFactoryBeanName(); // 若是建立这个Bean的工厂就是这个Bean自己的话,那么直接抛出异常 if (factoryBeanName != null) { if (factoryBeanName.equals(beanName)) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "factory-bean reference points back to the same bean definition"); } // 获得建立这个Bean的工厂Bean factoryBean = this.beanFactory.getBean(factoryBeanName); if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new ImplicitlyAppearedSingletonException(); } factoryClass = factoryBean.getClass(); isStatic = false; } else { // factoryBeanName为null,说明是经过静态工厂方法来实例化Bean的 // 静态工厂进行实例化Bean,beanClass属性必需要是工厂的class,若是为空,直接报错 if (!mbd.hasBeanClass()) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "bean definition declares neither a bean class nor a factory-bean reference"); } factoryBean = null; factoryClass = mbd.getBeanClass(); isStatic = true; } // 省略后续代码 }
小总结:
这段代码很简单,就是确认实例化当前这个Bean的工厂方法是静态工厂仍是实例工厂,若是是实例工厂,那么找出对应的工厂Bean。
public BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { // 省略第一段,第二段代码 // 到这里已经获得了一个BeanWrapper,明确了实例化当前这个Bean究竟是静态工厂仍是实例工厂 // 而且已经肯定了工厂Bean // 最终肯定的要用来建立对象的方法 Method factoryMethodToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; // 参数分析时已经说过,explicitArgs就是null if (explicitArgs != null) { argsToUse = explicitArgs; } else { // 下面这段代码是什么意思呢? // 在原型模式下,咱们会屡次建立一个Bean,因此Spring对参数以及所使用的方法作了缓存 // 在第二次建立原型对象的时候会进入这段缓存的逻辑 // 可是这里有个问题,为何Spring对参数有两个缓存呢? // 一:resolvedConstructorArguments // 二:preparedConstructorArguments // 这里主要是由于,直接使用解析好的构造的参数,由于这样会致使建立出来的全部Bean都引用同一个属性 Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; // 缓存已经解析过的工厂方法或者构造方法 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { // resolvedConstructorArguments跟preparedConstructorArguments都是对参数的缓存 argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; } } } if (argsToResolve != null) { // preparedConstructorArguments须要再次进行解析 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve); } } // 省略后续代码 }
小总结:
上面这段代码应该没什么大问题,其核心思想就是从缓存中取已经解析出来的方法以及参数,这段代码只会在原型模式下生效,由于单例的话对象只会建立一次嘛~!最大的问题在于,为何在对参数进行缓存的时候使用了两个不一样的集合,而且缓存后的参数还须要再次解析,这个问题咱们暂且放着,不妨带着这个问题往下看。
由于接下来要分析的代码就比较复杂了,因此为了让你完全看到代码的执行流程,下面我会使用示例+流程图+文字的方式来分析源码。
示例代码以下(这个例子覆盖接下来要分析的全部流程):
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="constructor"><!--这里开启自动注入,而且是经过构造函数进行自动注入--> <!--factoryObject 提供了建立对象的方法--> <bean id="factoryObject" class="com.dmz.spring.first.instantiation.service.FactoryObject"/> <!--提供一个用于测试自动注入的对象--> <bean class="com.dmz.spring.first.instantiation.service.OrderService" id="orderService"/> <!--主要测试这个对象的实例化过程--> <bean id="dmzService" factory-bean="factoryObject" factory-method="getDmz" scope="prototype"> <constructor-arg name="name" value="dmz"/> <constructor-arg name="age" value="18"/> <constructor-arg name="birthDay" value="2020-05-23"/> </bean> <!--测试静态方法实例化对象的过程--> <bean id="indexService" class="com.dmz.spring.first.instantiation.service.FactoryObject" factory-method="staticGetIndex"/> <!--提供这个转换器,用于转换dmzService中的birthDay属性,从字符串转换成日期对象--> <bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="conversionService"> <property name="converters"> <set> <bean class="com.dmz.spring.first.instantiation.service.ConverterStr2Date"/> </set> </property> </bean> </beans>
测试代码:
public class FactoryObject { public DmzService getDmz(String name, int age, Date birthDay, OrderService orderService) { System.out.println("getDmz with "+"name,age,birthDay and orderService"); return new DmzService(); } public DmzService getDmz(String name, int age, Date birthDay) { System.out.println("getDmz with "+"name,age,birthDay"); return new DmzService(); } public DmzService getDmz(String name, int age) { System.out.println("getDmz with "+"name,age"); return new DmzService(); } public DmzService getDmz() { System.out.println("getDmz with empty arg"); return new DmzService(); } public static IndexService staticGetIndex() { return new IndexService(); } } public class DmzService { } public class IndexService { } public class OrderService { } public class ConverterStr2Date implements Converter<String, Date> { @Override public Date convert(String source) { try { return new SimpleDateFormat("yyyy-MM-dd").parse(source); } catch (ParseException e) { return null; } } } /** * @author 程序员DMZ * @Date Create in 23:14 2020/5/21 * @Blog https://daimingzhi.blog.csdn.net/ */ public class Main { public static void main(String[] args) { ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext(); cc.setConfigLocation("application.xml"); cc.refresh(); cc.getBean("dmzService"); // 两次调用,用于测试缓存的方法及参数 // cc.getBean("dmzService"); } }
运行上面的代码会发现,程序打印:
getDmz with name,age,birthDay and orderService
具体缘由我相信你看了接下来的源码分析天然就懂了
public BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { // 第一段代码:到这里已经获得了一个BeanWrapper,并对这个BeanWrapper作了初始化 // 第二段代码:明确了实例化当前这个Bean究竟是静态工厂仍是实例工厂 // 第三段代码:以及从缓存中取过了对应了方法以及参数 // 进入第四段代码分析,执行到这段代码说明是第一次实例化这个对象 if (factoryMethodToUse == null || argsToUse == null) { // 若是被cglib代理的话,获取父类的class factoryClass = ClassUtils.getUserClass(factoryClass); // 获取到工厂类中的全部方法,接下来要一步步从这些方法中筛选出来符合要求的方法 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); List<Method> candidateList = new ArrayList<>(); // 第一步筛选:以前 在第二段代码中已经推断了方法是静态或者非静态的 // 因此这里第一个要求就是要知足静态/非静态这个条件 // 第二个要求就是必须符合bd中定义的factoryMethodName的名称 // 其中第二个要求请注意,若是bd是一个configurationClassBeanDefinition,也就是说是经过扫描@Bean注解产生的,那么在判断时还会添加是否标注了@Bean注解 for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { candidateList.add(candidate); } } // 将以前获得的方法集合转换成数组 // 到这一步获得的其实就是某一个方法的全部重载方法 // 好比dmz(),dmz(String name),dmz(String name,int age) Method[] candidates = candidateList.toArray(new Method[0]); // 排序,public跟参数多的优先级越高 AutowireUtils.sortFactoryMethods(candidates); // 用来保存从配置文件中解析出来的参数 ConstructorArgumentValues resolvedValues = null; // 是否使用了自动注入,本段代码中没有使用到这个属性,可是在后面用到了 boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); int minTypeDiffWeight = Integer.MAX_VALUE; // 可能出现多个符合要求的方法,用这个集合保存,实际上若是这个集合有值,就会抛出异常了 Set<Method> ambiguousFactoryMethods = null; int minNrOfArgs; // 一定为null,不考虑了 if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { // 就是说配置文件中指定了要使用的参数,那么须要对其进行解析,解析后的值就存储在resolvedValues这个集合中 if (mbd.hasConstructorArgumentValues()) { // 经过解析constructor-arg标签,将参数封装成了ConstructorArgumentValues // ConstructorArgumentValues这个类在下文咱们专门分析 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); // 解析标签中的属性,相似进行类型转换,后文进行详细分析 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } else { // 配置文件中没有指定要使用的参数,因此执行方法的最小参数个数就是0 minNrOfArgs = 0; } } // 省略后续代码.... }
小总结:
由于在实例化对象前一定要先肯定具体要使用的方法,因此这里先作的第一件事就是肯定要在哪一个范围内去推断要使用的factoryMethod呢?
最大的范围就是这个factoryClass的全部方法,也就是源码中的
rawCandidates
其次须要在
rawCandidates
中进一步作推断,由于在前面第二段代码的时候已经肯定了是静态方法仍是非静态方法,而且BeanDefinition
也指定了factoryMethodName,那么基于这两个条件这里就须要对rawCandidates
进一步进行筛选,获得一个candidateList
集合。咱们对示例的代码进行调试会发现
确实如咱们所料,
rawCandidates
是factoryClass中的全部方法,candidateList
是全部getDmz的重载方法。在肯定了推断factoryMethod的范围后,那么接下来要根据什么去肯定到底使用哪一个方法呢?换个问题,怎么区分这么些重载的方法呢?确定是根据方法参数嘛!
因此接下来要作的就是去解析要使用的参数了~
对于Spring而言,方法的参数会分为两种
- 配置文件中指定的
- 自动注入模式下,须要去容器中查找的
在上面的代码中,Spring就是将配置文件中指定的参数作了一次解析,对应方法就是
resolveConstructorArguments
。在查看这个方法的源码前,咱们先看看
ConstructorArgumentValues
这个类public class ConstructorArgumentValues { // 经过下标方式指定的参数 private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<>(); // 没有指定下标 private final List<ValueHolder> genericArgumentValues = new ArrayList<>(); // 省略无关代码..... }在前文的注释中咱们也说过了,它主要的做用就是封装解析
constructor-arg
标签获得的属性,解析标签对应的方法就是org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseConstructorArgElement
,这个方法我就不带你们看了,有兴趣的能够自行阅读。它主要有两个属性
- indexedArgumentValues
- genericArgumentValues
对应的就是咱们两种指定参数的方法,以下:
<bean id="dmzService" factory-bean="factoryObject" factory-method="getDmz" scope="prototype"> <constructor-arg name="name" value="dmz"/> <constructor-arg name="age" value="18"/> <constructor-arg index="2" value="2020-05-23"/> <!-- <constructor-arg name="birthDay" value="2020-05-23"/>--> </bean>其中的name跟age属性会被解析为
genericArgumentValues
,而index=2
会被解析为indexedArgumentValues
。在对
ConstructorArgumentValues
有必定认知以后,咱们再来看看resolveConstructorArguments
的代码:// 方法目的:解析配置文件中指定的方法参数 // beanName:bean名称 // mbd:beanName对应的beanDefinition // bw:经过它进行类型转换 // ConstructorArgumentValues cargs:解析标签获得的属性,尚未通过解析(类型转换) // ConstructorArgumentValues resolvedValues:已经通过解析的参数 // 返回值:返回方法须要的最小参数个数 private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) { // 是否有定制的类型转换器,没有的话直接使用BeanWrapper进行类型转换 TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); TypeConverter converter = (customConverter != null ? customConverter : bw); // 构造一个BeanDefinitionValueResolver,专门用于解析constructor-arg中的value属性,实际上还包括ref属性,内嵌bean标签等等 BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); // minNrOfArgs 记录执行方法要求的最小参数个数,通常状况下就是等于constructor-arg标签指定的参数数量 int minNrOfArgs = cargs.getArgumentCount(); for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) { int index = entry.getKey(); if (index < 0) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid constructor argument index: " + index); } // 这是啥意思呢? // 这个代码我认为是有问题的,而且我给Spring官方已经提了一个issue,官方将会在5.2.7版本中修复 // 暂且你先这样理解 // 假设A方法直接在配置文件中指定了index=3上要使用的参数,那么这个时候A方法至少须要4个参数 // 可是其他的3个参数可能不是经过constructor-arg标签指定的,而是直接自动注入进来的,那么在配置文件中咱们就只配置了index=3上的参数,也就是说 int minNrOfArgs = cargs.getArgumentCount()=1,这个时候 index=3,minNrOfArgs=1, 因此 minNrOfArgs = 3+1 if (index > minNrOfArgs) { minNrOfArgs = index + 1; } ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue(); // 若是已经转换过了,直接添加到resolvedValues集合中 if (valueHolder.isConverted()) { resolvedValues.addIndexedArgumentValue(index, valueHolder); } else { // 解析value/ref/内嵌bean标签等 Object resolvedValue = valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue()); // 将解析后的resolvedValue封装成一个新的ValueHolder,并将其source设置为解析constructor-arg获得的那个ValueHolder,后期会用到这个属性进行判断 ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName()); resolvedValueHolder.setSource(valueHolder); resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder); } } // 对getGenericArgumentValues进行解析,代码基本同样,再也不赘述 return minNrOfArgs; }能够看到,最终的解析逻辑就在
resolveValueIfNecessary
这个方法中,那么这个方法又作了什么呢?// 这个方法的目的就是将解析constructor-arg标签获得的value值进行一次解析 // 在解析标签时ref属性会被封装为RuntimeBeanReference,那么在这里进行解析时就会去调用getBean // 在解析value属性会会被封装为TypedStringValue,那么这里会尝试去进行一个转换 // 关于标签的解析你们有兴趣的话能够去看看org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parsePropertyValue // 这里再也不赘述了 public Object resolveValueIfNecessary(Object argName, @Nullable Object value) { // 解析constructor-arg标签中的ref属性,实际就是调用了getBean if (value instanceof RuntimeBeanReference) { RuntimeBeanReference ref = (RuntimeBeanReference) value; return resolveReference(argName, ref); } // ...... /** * <constructor-arg> * <set value-type="java.lang.String"> * <value>1</value> * </set> * </constructor-arg> * 经过上面set标签中的value-type属性对value进行类型转换, * 若是value-type属性为空,那么这里不会进行类型转换 */ else if (value instanceof TypedStringValue) { TypedStringValue typedStringValue = (TypedStringValue) value; Object valueObject = evaluate(typedStringValue); try { Class<?> resolvedTargetType = resolveTargetType(typedStringValue); if (resolvedTargetType != null) { return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); } else { return valueObject; } } catch (Throwable ex) { // Improve the message by showing the context. throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, ex); } } // 省略后续代码.... }就咱们上面的例子而言,通过
resolveValueIfNecessary
方法并不能产生实际的影响,由于在XML中咱们没有配置ref属性或者value-type属性。画图以下:
public BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { // 第一段代码:到这里已经获得了一个BeanWrapper,并对这个BeanWrapper作了初始化 // 第二段代码:明确了实例化当前这个Bean究竟是静态工厂仍是实例工厂 // 第三段代码:以及从缓存中取过了对应了方法以及参数 // 第四段代码:明确了方法须要的最小的参数数量并对配置文件中的标签属性进行了一次解析 // 进入第五段代码分析 // 保存在建立方法参数数组过程当中发生的异常,若是最终没有找到合适的方法,那么将这个异常信息封装后抛出 LinkedList<UnsatisfiedDependencyException> causes = null; // 开始遍历全部在第四段代码中查询到的符合要求的方法 for (Method candidate : candidates) { // 方法的参数类型 Class<?>[] paramTypes = candidate.getParameterTypes(); // 候选的方法的参数必需要大于在第四段这推断出来的最小参数个数 if (paramTypes.length >= minNrOfArgs) { ArgumentsHolder argsHolder; // 一定为null,不考虑 if (explicitArgs != null) { // Explicit arguments given -> arguments length must match exactly. if (paramTypes.length != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } else { // Resolved constructor arguments: type conversion and/or autowiring necessary. try { // 获取参数的具体名称 String[] paramNames = null; ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } // 根据方法的参数名称以及配置文件中配置的参数建立一个参数数组用于执行工厂方法 argsHolder = createArgumentArray( beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring); } // 在建立参数数组的时候可能发生异常,这个时候的异常不能直接抛出,要确保全部的候选方法遍历完成,只要有一个方法符合要求便可,可是若是遍历完全部方法仍是没找到合适的构造器,那么直接抛出这些异常 catch (UnsatisfiedDependencyException ex) { if (logger.isTraceEnabled()) { logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex); } // Swallow and try next overloaded factory method. if (causes == null) { causes = new LinkedList<>(); } causes.add(ex); continue; } // 计算类型差别 // 首先判断bd中是宽松模式仍是严格模式,目前看来只有@Bean标注的方法解析获得的Bean会使用严格模式来计算类型差别,其他都是使用宽松模式 // 严格模式下, int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // 选择一个类型差别最小的方法 if (typeDiffWeight < minTypeDiffWeight) { factoryMethodToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousFactoryMethods = null; } // 省略后续代码....... }
小总结:这段代码的核心思想就是根据
第四段
代码从配置文件中解析出来的参数构造方法执行所须要的实际参数数组。若是构建成功就表明这个方法能够用于实例化Bean,而后计算实际使用的参数跟方法上申明的参数的”差别值“,并在全部符合要求的方法中选择一个差别值最小的方法接下来,咱们来分析方法实现的细节
- 构建方法使用的参数数组,也就是
createArgumentArray
方法,其源码以下:/* beanName:要实例化的Bean的名称 * mbd:对应Bean的BeanDefinition * resolvedValues:从配置文件中解析出来的并尝试过类型转换的参数 * bw:在这里主要就是用做类型转换器 * paramTypes:当前遍历到的候选的方法的参数类型数组 * paramNames:当前遍历到的候选的方法的参数名称 * executable:当前遍历到的候选的方法 * autowiring:是否时自动注入 */ private ArgumentsHolder createArgumentArray( String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues, BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable, boolean autowiring) throws UnsatisfiedDependencyException { TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); TypeConverter converter = (customConverter != null ? customConverter : bw); ArgumentsHolder args = new ArgumentsHolder(paramTypes.length); Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length); Set<String> autowiredBeanNames = new LinkedHashSet<>(4); // 遍历候选方法的参数,跟据方法实际须要的类型到resolvedValues中去匹配 for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) { Class<?> paramType = paramTypes[paramIndex]; String paramName = (paramNames != null ? paramNames[paramIndex] : ""); ConstructorArgumentValues.ValueHolder valueHolder = null; if (resolvedValues != null) { // 首先,根据方法参数的下标到resolvedValues中找对应的下标的属性 // 若是没找到再根据方法的参数名/类型去resolvedValues查找 valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders); // 若是都没找到 // 1.是自动注入而且方法的参数长度正好跟配置中的参数数量相等 // 2.不是自动注入 // 那么按照顺序一次选取 if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) { valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders); } } // 也就是说在配置的参数中找到了合适的值能够应用于这个方法上 if (valueHolder != null) { // 防止同一个参数被应用了屡次 usedValueHolders.add(valueHolder); Object originalValue = valueHolder.getValue(); Object convertedValue; // 已经进行过类型转换就不会须要再次进行类型转换 if (valueHolder.isConverted()) { convertedValue = valueHolder.getConvertedValue(); args.preparedArguments[paramIndex] = convertedValue; } else { // 尝试将配置的值转换成方法参数须要的类型 MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex); try { // 进行类型转换 convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam); } catch (TypeMismatchException ex) { // 抛出UnsatisfiedDependencyException,在调用该方法处会被捕获 } Object sourceHolder = valueHolder.getSource(); // 只要是valueHolder存在,到这里这个判断一定成立 if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) { Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue(); args.resolveNecessary = true; args.preparedArguments[paramIndex] = sourceValue; } } args.arguments[paramIndex] = convertedValue; args.rawArguments[paramIndex] = originalValue; } else { // 方法执行须要参数,可是resolvedValues中没有提供这个参数,也就是说这个参数是要自动注入到Bean中的 MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex); // 不是自动注入,直接抛出异常 if (!autowiring) { // 抛出UnsatisfiedDependencyException,在调用该方法处会被捕获 } try { // 自动注入的状况下,调用getBean获取须要注入的Bean Object autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter); // 把getBean返回的Bean封装到本次方法执行时须要的参数数组中去 args.rawArguments[paramIndex] = autowiredArgument; args.arguments[paramIndex] = autowiredArgument; // 标志这个参数是自动注入的 args.preparedArguments[paramIndex] = new AutowiredArgumentMarker(); // 自动注入的状况下,在第二次调用时,须要从新处理,不能直接缓存 args.resolveNecessary = true; } catch (BeansException ex) { // 抛出UnsatisfiedDependencyException,在调用该方法处会被捕获 } } } // 注册Bean之间的依赖关系 for (String autowiredBeanName : autowiredBeanNames) { this.beanFactory.registerDependentBean(autowiredBeanName, beanName); if (logger.isDebugEnabled()) { logger.debug("Autowiring by type from bean name '" + beanName + "' via " + (executable instanceof Constructor ? "constructor" : "factory method") + " to bean named '" + autowiredBeanName + "'"); } } return args; }上面这段代码说难也难,说简单也简单,若是要完全看懂它到底干了什么仍是颇有难度的。简单来讲,它就是从第四段代码解析出来的参数中查找当前的这个候选方法须要的参数。若是找到了,那么尝试对其进行类型转换,将其转换成符合方法要求的类型,若是没有找到那么还须要判断当前方法的这个参数能不能进行自动注入,若是能够自动注入的话,那么调用getBean获得须要的Bean,并将其注入到方法须要的参数中。
public BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { // 第一段代码:到这里已经获得了一个BeanWrapper,并对这个BeanWrapper作了初始化 // 第二段代码:明确了实例化当前这个Bean究竟是静态工厂仍是实例工厂 // 第三段代码:以及从缓存中取过了对应了方法以及参数 // 第四段代码:明确了方法须要的最小的参数数量并对配置文件中的标签属性进行了一次解析 // 第五段代码:到这里已经肯定了可使用来实例化Bean的方法是哪一个 // 省略抛出异常的代码,就是在对推断出来的方法作验证 // 1.推断出来的方法不能为null // 2.推断出来的方法返回值不能为void // 3.推断出来的方法不能有多个 // 对参数进行缓存 if (explicitArgs == null && argsHolderToUse != null) { argsHolderToUse.storeCache(mbd, factoryMethodToUse); } } try { Object beanInstance; if (System.getSecurityManager() != null) { final Object fb = factoryBean; final Method factoryMethod = factoryMethodToUse; final Object[] args = argsToUse; beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, beanFactory, fb, factoryMethod, args), beanFactory.getAccessControlContext()); } else { // 反射调用对应方法进行实例化 // 1.获取InstantiationStrategy,主要就是SimpleInstantiationStrategy跟CglibSubclassingInstantiationStrategy,其中CglibSubclassingInstantiationStrategy主要是用来处理beanDefinition中的lookupMethod跟replaceMethod。一般来讲咱们使用的就是SimpleInstantiationStrateg // 2.SimpleInstantiationStrateg就是单纯的经过反射调用方法 beanInstance = this.beanFactory.getInstantiationStrategy().instantiate( mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse); } // beanWrapper在这里对Bean进行了包装 bw.setBeanInstance(beanInstance); return bw; } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean instantiation via factory method failed", ex); } }
上面这段代码的主要目的就是
- 缓存参数,原型可能屡次建立同一个对象
- 反射调用推断出来的factoryMethod
若是上面你对使用factoryMethd进行实例化对象已经足够了解的话,那么下面的源码分析基本没有什么很大区别,咱们接着看看代码。
首先,咱们回到createBeanInstance
方法中,
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 上面的代码已经分析过了 // 1.使用supplier来获得一个对象 // 2.经过factotryMethod方法实例化一个对象 // 看起来是否是有点熟悉,在使用factotryMethod建立对象时也有差很少这样的一段代码,看起来就是使用缓存好的方法直接建立一个对象 boolean resolved = false; boolean autowireNecessary = false; // 不对这个参数进行讨论,就认为一直为null if (args == null) { synchronized (mbd.constructorArgumentLock) { // bd中的resolvedConstructorOrFactoryMethod不为空,说明已经解析过构造方法了 if (mbd.resolvedConstructorOrFactoryMethod != null) { // resolved标志是否解析过构造方法 resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { // 构造函数已经解析过了,而且这个构造函数在调用时须要自动注入参数 if (autowireNecessary) { // 此时部分解析好的参数已经存在了beanDefinition中,而且构造函数也在bd中 // 那么在这里只会从缓存中去取构造函数以及参数而后反射调用 return autowireConstructor(beanName, mbd, null, null); } else { // 这里就是直接反射调用空参构造 return instantiateBean(beanName, mbd); } } // 推断出可以使用的须要参数的构造函数 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); // 在推断出来的构造函数中选取一个合适的方法来进行Bean的实例化 // ctors不为null:说明存在1个或多个@Autowired标注的方法 // mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR:说明是自动注入 // mbd.hasConstructorArgumentValues():配置文件中配置了构造函数要使用的参数 // !ObjectUtils.isEmpty(args):外部传入的参数,一定为null,很少考虑 // 上面的条件只要知足一个就会进入到autowireConstructor方法 // 第一个条件知足,那么经过autowireConstructor在推断出来的构造函数中再进一步选择一个差别值最小的,参数最长的构造函数 // 第二个条件知足,说明没有@Autowired标注的方法,可是须要进行自动注入,那么经过autowireConstructor会去遍历类中申明的全部构造函数,并查找一个差别值最小的,参数最长的构造函数 // 第三个条件知足,说明不是自动注入,那么要经过配置中的参数去类中申明的全部构造函数中匹配 // 第四个一定为null,不考虑 if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 反射调用空参构造 return instantiateBean(beanName, mbd); }
由于autowireConstructor
方法的执行逻辑跟instantiateUsingFactoryMethod
方法的执行逻辑基本一致,只是将Method
对象换成了Constructor
对象,因此对这个方法我再也不作详细的分析。
咱们主要就看看determineConstructorsFromBeanPostProcessors
这个方法吧,这个方法的主要目的就是推断出候选的构造方法。
// 实际调用的就是AutowiredAnnotationBeanPostProcessor中的determineCandidateConstructors方法 // 这个方法看起来很长,但实际确很简单,就是经过@Autowired注解肯定哪些构造方法能够做为候选方法,其实在使用factoryMethod来实例化对象的时候也有这种逻辑在其中,后续在总结的时候咱们对比一下 public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException { // 这里作的事情很简单,就是将@Lookup注解标注的方法封装成LookupOverride添加到BeanDefinition中的methodOverrides属性中,若是这个属性不为空,在实例化对象的时候不能选用SimpleInstantiationStrateg,而要使用CglibSubclassingInstantiationStrategy,经过cglib代理给方法加一层拦截了逻辑 // 避免重复检查 if (!this.lookupMethodsChecked.contains(beanName)) { try { ReflectionUtils.doWithMethods(beanClass, method -> { Lookup lookup = method.getAnnotation(Lookup.class); if (lookup != null) { Assert.state(this.beanFactory != null, "No BeanFactory available"); // 将@Lookup注解标注的方法封装成LookupOverride LookupOverride override = new LookupOverride(method, lookup.value()); try { // 添加到BeanDefinition中的methodOverrides属性中 RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName); mbd.getMethodOverrides().addOverride(override); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(beanName, "Cannot apply @Lookup to beans without corresponding bean definition"); } } }); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Lookup method resolution failed", ex); } this.lookupMethodsChecked.add(beanName); } // 接下来要开始肯定到底哪些构造函数能被做为候选者 // 先尝试从缓存中获取 Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass); if (candidateConstructors == null) { // Fully synchronized resolution now... synchronized (this.candidateConstructorsCache) { candidateConstructors = this.candidateConstructorsCache.get(beanClass);、 // 缓存中没法获取到,进入正式的推断过程 if (candidateConstructors == null) { Constructor<?>[] rawCandidates; try { // 第一步:先查询这个类全部的构造函数,包括私有的 rawCandidates = beanClass.getDeclaredConstructors(); } catch (Throwable ex) { // 省略异常信息 } List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length); // 保存添加了Autowired注解而且required属性为true的构造方法 Constructor<?> requiredConstructor = null; // 空参构造 Constructor<?> defaultConstructor = null; // 看方法注释上说明的,这里除非是kotlin的类,不然一定为null,不作过多考虑,咱们就将其看成null Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass); int nonSyntheticConstructors = 0; // 对类中的全部构造方法进行遍历 for (Constructor<?> candidate : rawCandidates) { // 非合成方法 if (!candidate.isSynthetic()) { nonSyntheticConstructors++; } else if (primaryConstructor != null) { continue; } // 查询方法上是否有Autowired注解 AnnotationAttributes ann = findAutowiredAnnotation(candidate); if (ann == null) { // userClass != beanClass说明这个类进行了cglib代理 Class<?> userClass = ClassUtils.getUserClass(beanClass); if (userClass != beanClass) { try { // 若是进行了cglib代理,那么在父类上再次查找Autowired注解 Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes()); ann = findAutowiredAnnotation(superCtor); } catch (NoSuchMethodException ex) { // Simply proceed, no equivalent superclass constructor found... } } } // 说明当前的这个构造函数上有Autowired注解 if (ann != null) { if (requiredConstructor != null) { // 省略异常抛出 } // 获取Autowired注解中的required属性 boolean required = determineRequiredStatus(ann); if (required) { // 类中存在多个@Autowired标注的方法,而且某个方法的@Autowired注解上被申明了required属性要为true,那么直接报错 if (!candidates.isEmpty()) { // 省略异常抛出 } requiredConstructor = candidate; } // 添加到集合中,这个集合存储的都是被@Autowired注解标注的方法 candidates.add(candidate); } // 空参构造函数 else if (candidate.getParameterCount() == 0) { defaultConstructor = candidate; } } if (!candidates.isEmpty()) { // 存在多个被@Autowired标注的方法 // 而且全部的required属性被设置成了false (默认为true) if (requiredConstructor == null) { // 存在空参构造函数,注意,空参构造函数能够不被@Autowired注解标注 if (defaultConstructor != null) { // 将空参构造函数也加入到候选的方法中去 candidates.add(defaultConstructor); } // 省略日志打印 } candidateConstructors = candidates.toArray(new Constructor<?>[0]); } // 也就是说,类中只提供了一个构造函数,而且这个构造函数不是空参构造函数 else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) { candidateConstructors = new Constructor<?>[] {rawCandidates[0]}; } // 省略中间两个判断,primaryConstructor一定为null,不考虑 // ..... } else { // 说明没法推断出来 candidateConstructors = new Constructor<?>[0]; } this.candidateConstructorsCache.put(beanClass, candidateConstructors); } } } return (candidateConstructors.length > 0 ? candidateConstructors : null); }
这里我简单总结下这个方法的做用
获取到类中的全部构造函数
查找到被
@Autowired
注解标注的构造函数
- 若是存在多个被
@Autowired
标注的构造函数,而且其required属性没有被设置为true,那么返回这些被标注的函数的集合(空参构造即便没有添加@Autowired
也会被添加到集合中)- 若是存在多个被
@Autowired
标注的构造函数,而且其中一个的required属性被设置成了true,那么直接报错- 若是只有一个构造函数被
@Autowired
标注,而且其required属性被设置成了true,那么直接返回这个构造函数若是没有被
@Autowired
标注标注的构造函数,可是类中有且只有一个构造函数,而且这个构造函数不是空参构造函数,那么返回这个构造函数上面的条件都不知足,那么
determineCandidateConstructors
这个方法就没法推断出合适的构造函数了
能够看到,经过AutowiredAnnotationBeanPostProcessor
的determineCandidateConstructors
方法能够处理构造函数上的@Autowired
注解。
可是,请注意,这个方法并不能决定到底使用哪一个构造函数来建立对象(即便它只推断出来一个,也不必定可以使用),它只是经过@Autowired
注解来肯定构造函数的候选者,在构造函数都没有添加@Autowired
注解的状况下,这个方法推断不出来任何方法。真正肯定到底使用哪一个构造函数是交由autowireConstructor
方法来决定的。前文已经分析过了instantiateUsingFactoryMethod
方法,autowireConstructor
的逻辑基本跟它一致,因此这里再也不作详细的分析。
从上图中能够看到,总体逻辑上它们并无什么区别,只是查找的对象从factoryMethod换成了构造函数
细节的差别主要体如今推断方法上
它们之间的差别我已经在图中标识出来了,主要就是两点
- 经过构造函数实例化对象,多了一层处理,就是要处理构造函数上的@Autowired注解以及方法上的@LookUp注解(要决定选取哪种实例化策略,
SimpleInstantiationStrategy
/CglibSubclassingInstantiationStrategy
)- 在最终的选取也存在差别,对于facotyMehod而言,在宽松模式下(
除ConfigurationClassBeanDefinition
外,也就是扫描@Bean获得的BeanDefinition,都是宽松模式),会选取一个最精准的方法,在严格模式下,会选取一个参数最长的方法- 对于构造函数而言,会一定会选取一个参数最长的方法
思考了好久,我仍是决定再补充一些内容,就是关于上面两幅图的最后一步,对应的核心代码以下:
int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); if (typeDiffWeight < minTypeDiffWeight) { factoryMethodToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousFactoryMethods = null; }
判断bd是严格模式仍是宽松模式,上面说过不少次了,bd默认就是宽松模式,只要在ConfigurationClassBeanDefinition
中使用严格模式,也就是扫描@Bean标注的方法注册的bd(对应的代码能够参考:org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod
方法)
咱们再看看严格模式跟宽松模式在计算差别值时的区别
public int getTypeDifferenceWeight(Class<?>[] paramTypes) { // 计算实际使用的参数跟方法申明的参数的差别值 int typeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments); // 计算没有通过类型转换的参数跟方法申明的参数的差别值 int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024; return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight); } public static int getTypeDifferenceWeight(Class<?>[] paramTypes, Object[] args) { int result = 0; for (int i = 0; i < paramTypes.length; i++) { // 在出现类型转换时,下面这个判断才会成立,也就是在比较rawArguments跟paramTypes的差别时才可能知足这个条件 if (!ClassUtils.isAssignableValue(paramTypes[i], args[i])) { return Integer.MAX_VALUE; } if (args[i] != null) { Class<?> paramType = paramTypes[i]; Class<?> superClass = args[i].getClass().getSuperclass(); while (superClass != null) { // 若是咱们传入的值是方法上申明的参数的子类,那么每多一层继承关系,差别值加2 if (paramType.equals(superClass)) { result = result + 2; superClass = null; } else if (ClassUtils.isAssignable(paramType, superClass)) { result = result + 2; superClass = superClass.getSuperclass(); } else { superClass = null; } } // 判断方法的参数是否是一个接口,若是是,那么差别值加1 if (paramType.isInterface()) { result = result + 1; } } } return result; }
public int getAssignabilityWeight(Class<?>[] paramTypes) { // 严格模式下,只有三种返回值 // 1.Integer.MAX_VALUE,通过类型转换后仍是不符合要求,返回最大的类型差别 // 由于解析后的参数可能返回一个NullBean(建立对象的方法返回了null,Spring会将其包装成一个NullBean),不过通常不会出现这种状况,因此咱们能够当这种状况不存在 for (int i = 0; i < paramTypes.length; i++) { if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) { return Integer.MAX_VALUE; } } // 2.Integer.MAX_VALUE - 512,进行过了类型转换才符合要求 for (int i = 0; i < paramTypes.length; i++) { if (!ClassUtils.isAssignableValue(paramTypes[i], this.rawArguments[i])) { return Integer.MAX_VALUE - 512; } } // 3.Integer.MAX_VALUE - 1024,没有通过类型转换就已经符合要求了,返回最小的类型差别 return Integer.MAX_VALUE - 1024; }
首先,无论是factoryMethod仍是constructor,都是采用上面的两个方法来计算类型差别,可是正常来讲,只有factoryMethod会采用到严格模式(除非程序员手动干预,好比经过Bean工厂后置处理器修改了bd中的属性,这样一般来讲没有很大意义)
因此咱们分为三种状况讨论
这种状况下,会选取一个最精确的方法,同时方法的参数要尽可能长
测试代码:
public class FactoryObject { public DmzService getDmz() { System.out.println(0); return new DmzService(); } public DmzService getDmz(OrderService indexService) { System.out.println(1); return new DmzService(); } public DmzService getDmz(OrderService orderService, IndexService indexService) { System.out.println(2); return new DmzService(); } public DmzService getDmz(OrderService orderService, IndexService indexService,IA ia) { System.out.println(3); return new DmzService(); } } public class ServiceImpl implements IService { } public class IAImpl implements IA { }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="constructor"><!--必需要开启自动注入,而且是经过构造函数进行自动注入,不然选用无参构造--> <!--factoryObject 提供了建立对象的方法--> <bean id="factoryObject" class="com.dmz.spring.instantiation.service.FactoryObject"/> <bean class="com.dmz.spring.instantiation.service.OrderService" id="orderService"/> <bean id="dmzService" factory-bean="factoryObject" factory-method="getDmz" /> <bean class="com.dmz.spring.instantiation.service.ServiceImpl" id="iService"/> <bean class="com.dmz.spring.instantiation.service.IndexService" id="indexService"/> </beans>
/** * @author 程序员DMZ * @Date Create in 23:59 2020/6/1 * @Blog https://daimingzhi.blog.csdn.net/ */ public class XMLMain { public static void main(String[] args) { ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("application.xml"); } }
运行程序发现,选用了第三个(getDmz(OrderService orderService, IndexService indexService)
)构造方法。虽然最后一个方法的参数更长,可是由于其方法申明的参数上存在接口,因此它的差别值会大于第三个方法,由于不会被选用
这种状况下,会选取一个参数尽可能长的方法
测试代码:
/** * @author 程序员DMZ * @Date Create in 6:28 2020/6/1 * @Blog https://daimingzhi.blog.csdn.net/ */ @ComponentScan("com.dmz.spring.instantiation") @Configuration public class Config { @Bean public DmzService dmzService() { System.out.println(0); return new DmzService(); } @Bean public DmzService dmzService(OrderService indexService) { System.out.println(1); return new DmzService(); } @Bean public DmzService dmzService(OrderService orderService, IndexService indexService) { System.out.println(2); return new DmzService(); } @Bean public DmzService dmzService(OrderService orderService, IndexService indexService, IA ia) { System.out.println("config " +3); return new DmzService(); } @Bean public DmzService dmzService(OrderService orderService, IndexService indexService, IA ia, IService iService) { System.out.println("config " +4); return new DmzService(); } } /** * @author 程序员DMZ * @Date Create in 6:29 2020/6/1 * @Blog https://daimingzhi.blog.csdn.net/ */ public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.register(Config.class); ac.refresh(); } }
运行程序,发现选用了最后一个构造函数,这是由于在遍历候选方法时,会先遍历参数最长的,而在计算类型差别时,由于严格模式下,上面全部方法的差别值都是同样的,都会返回Integer.MAX_VALUE - 1024
。实际上,在不进行手动干预的状况下,都会返沪这个值。
这种状况下,也会选取一个参数尽可能长的方法
之因此会这样,主要是由于在autowireConstructor
方法中进行了一次短路判断,以下所示:
在上图中,若是已经找到了合适的方法,那么直接就不会再找了,而在遍历的时候是从参数最长的方法开始遍历的,测试代码以下:
@Component public class DmzService { // 没有添加@Autowired注解,也会被看成候选方法 public DmzService(){ System.out.println(0); } @Autowired(required = false) public DmzService(OrderService orderService) { System.out.println(1); } @Autowired(required = false) public DmzService(OrderService orderService, IService iService) { System.out.println(2); } @Autowired(required = false) public DmzService(OrderService orderService, IndexService indexService, IService iService,IA ia) { System.out.println("DmzService "+3); } } /** * @author 程序员DMZ * @Date Create in 6:29 2020/6/1 * @Blog https://daimingzhi.blog.csdn.net/ */ public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.register(Config.class); ac.refresh(); } }
这篇文章就到这里啦~~!
文章很长,但愿你耐心看完,码字不易,若是有帮助到你的话点个赞吧~!
扫描下方二维码,关注个人公众号,更多精彩文章在等您!~~