专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

分析一波Spring中factory-method如何实例化对象的?

你的赞是我最大的动力,期待与你的共同进步。

1.回顾

  文章开篇,不得不前情提要走一波了。还记得 @Configuration 类中的@Bean方法是如何处理的吗?@Bean方法中的对象是如何实例化的?小小的脑袋上面是否有大大的问号呢? 这里做一个简要回顾,首先看 @Bean 方法的处理: 121_1.png   然后在通过下面以系列的方法对其解析: 121_2.png

  上述图片中的最后一步,是不是很亲切?是不是看到了熟悉的 registerBeanDefinition()方法?是不是还能想起 this.beanDefinitionMap.put(beanName , beanDefinition);

  最后转化成相应的 BeanDefinition 注册到 BeanDefinitionMap 中去: 121_3.png

  首先我们其中一个 BeanDefinition 为例,从上图中查看这个 BeanDefinition 中都包含哪些信息。 121_4.png

  这里看到,将 BeanDefinition 注册到 Map 中去了,但是这里这个注册并不是这么简单的。这里要对一下几种情况加以区分,要不然看到后面的 instantiateUsingFactoryMethod() 方法肯定会懵圈的。下面我们紧接着来分析分析 @Bean的处理情形…

  验证几种情形的需要的类:

public class DemoServiceOne {
 @Autowired
 DemoServiceTwo demoServiceTwo;
 public DemoServiceOne(){

 } public DemoServiceOne(DemoServiceTwo demoServiceTwo){ this.demoServiceTwo = demoServiceTwo; } } 
@Service
public class DemoServiceTwo {
}

public class BeanDemoOne {
}

public class FactoryBeanDemoOne implements FactoryBean<BeanDemoOne> {
 @Override
 public BeanDemoOne getObject() throws Exception {
  return new BeanDemoOne();
 }
 @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } public FactoryBeanDemoOne (){} public FactoryBeanDemoOne (int i){ } } 

1.1 静态的 @Bean 方法

@Configuration
@ComponentScan("com.demo")
public class DemoConfigOne {

 @Bean("demoService")
 public static DemoServiceOne demoServiceOne(){ return new DemoServiceOne(); } } 

121_5.pngsituation_01

1.2 非静态的构造方法

@Configuration
@ComponentScan("com.demo")
public class DemoConfigOne {

 @Bean
 public FactoryBeanDemoOne demoFactoryBean() { return new FactoryBeanDemoOne(); } } 

121_6.pngsituation_02

1.3 通过两个 @Bean 返回同类型的对象

@Configuration
@ComponentScan("com.demo")
public class DemoConfigOne {

     @Bean
 public FactoryBeanDemoOne demoFactoryBean() { return new FactoryBeanDemoOne(); } @Bean public FactoryBeanDemoOne demoFactoryBean() { return new FactoryBeanDemoOne(); } } 

121_7.pngsituation_03

1.4 通过两个 @Bean 返回指定名称的同类型对象

@Configuration
@ComponentScan("com.demo")
public class DemoConfigOne {

  @Bean("demoOne")
 public DemoServiceOne demoServiceOne(DemoServiceTwo demoServiceTwo){ return new DemoServiceOne(demoServiceTwo); } @Bean("demoTwo") public DemoServiceOne demoServiceOne(){ return new DemoServiceOne(); } } 

121_8.pngsituation_04

2.通过工厂方法创建实例

  在不禁感慨Spring的强大的同时,在看到某些方法的时候,也觉得某些方法好像不是那么符合Spring的设计?下面这个方法,就是写的比较绕的方法, 没有办法,只能硬着头皮往下看。。。

public BeanWrapper instantiateUsingFactoryMethod(
        String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

    // 构造 BeanWrapperImpl 对象
    BeanWrapperImpl bw = new BeanWrapperImpl();
 /* * 初始化 BeanWrapperImpl * 向BeanWrapper对象中添加 ConversionService 对象和属性编辑器 PropertyEditor 对象 */ this.beanFactory.initBeanWrapper(bw); Object factoryBean; Class<?> factoryClass; boolean isStatic; // 通过beanDefinition获取到factoryBeanName ,实际就是@Bean注解的方法 所在的 configuration类 String factoryBeanName = mbd.getFactoryBeanName(); if (factoryBeanName != null) { // factoryBeanName 与 当前的 beanName 相同 抛出异常 if (factoryBeanName.equals(beanName)) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "factory-bean reference points back to the same bean definition"); } // 根据 BeanName 获取 对象,就是 @Configuration 注解的类 这里获取到的是被 CGLIB 代理的类 factoryBean = this.beanFactory.getBean(factoryBeanName); if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new ImplicitlyAppearedSingletonException(); } // 获取工厂类 factoryClass = factoryBean.getClass(); isStatic = false; } else { // 工厂名称为空,则可能是一个静态工厂 // 如果有static 且为工厂方法,则添加到 candidateList 中 // 这加这个判断是以防漏掉 加了 static 的 @Bean 方法。当然,没有加 @Bean 的方法就不会被考虑了 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; } // 工厂方法 Method factoryMethodToUse = null; // 持有的参数 ArgumentsHolder argsHolderToUse = null; // 使用的参数 Object[] argsToUse = null; /* * 工厂方法的参数,如果指定了构造参数,则直接使用 * @Bean注解的方法(工厂方法)的参数,在启动过程中实例化的对象 这里一般都为null,即一般不指定参数 * 追溯来源:就是 getBean() 方法中的 args 为null */ if (explicitArgs != null) { argsToUse = explicitArgs; } else { // 没有指定 Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { // 首先尝试从缓存中获取 factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; // 获取缓存中的构造函数或者工厂方法,不为空表示已经使用过工厂方法,那么这里会再次使用 // 一般原型模式和Scope模式采用的上,直接使用该工厂方法和缓存的参数 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { // 获取缓存中的构造参数 argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; } } } // 缓存中存在,则解析存储在 BeanDefinition 中的参数 // 如给定方法的构造函数 A(int ,int ),则通过此方法后就会把配置文件中的("1","1")转换为 (1,1) // 缓存中的值可能是原始值也有可能是最终值 if (argsToResolve != null) { argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true); } } // getBean() 方法没有传参数 或 没有使用过 工厂方法 if (factoryMethodToUse == null || argsToUse == null) { // 获取工厂方法的类全名称 factoryClass = ClassUtils.getUserClass(factoryClass); // 获取所有声明的构造方法,默认允许访问非公开的方法 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); // 检索所有方法,这里是对方法进行过滤 List<Method> candidateList = new ArrayList<>(); for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { // 添加到候选类里面去 candidateList.add(candidate); } } /** * candidateList.size() == 1 表示待定的方法只有一个 * explicitArgs == null 调用getBean方法时没有传参 * !mbd.hasConstructorArgumentValues() 没有缓存过参数, * 直接通过调用实例化方法执行该候选方法 */ if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Method uniqueCandidate = candidateList.get(0); if (uniqueCandidate.getParameterCount() == 0) { mbd.factoryMethodToIntrospect = uniqueCandidate; synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; mbd.constructorArgumentsResolved = true; mbd.resolvedConstructorArguments = EMPTY_ARGS; } bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS)); // 返回 return bw; } } Method[] candidates = candidateList.toArray(new Method[0]); // 排序构造函数 // public 构造函数优先参数数量降序,非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; // 如果调用getBean方法时有传参,那么工厂方法最少参数个数要等于传参个数 if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { // getBean() 没有传递参数,则需要解析保存在 BeanDefinition 构造函数中指定的参数 if (mbd.hasConstructorArgumentValues()) { // 构造函数的参数 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); // 解析构造函数的参数 // 将该 bean 的构造函数参数解析为 resolvedValues 对象,其中会涉及到其他 bean resolvedValues = new ConstructorArgumentValues(); // 解析构造函数的参数 返回对应的参数个数 赋值给最小参数个数变量 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } else { minNrOfArgs = 0; } } LinkedList<UnsatisfiedDependencyException> causes = null; // 遍历候选方法 (这里拿到的其实就是实例化 Bean 的构造方法) for (Method candidate : candidates) { // 方法的参数列表 Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) { // 保存参数的对象 ArgumentsHolder argsHolder; // getBean()传递了参数 if (explicitArgs != null) { // 显示给定参数,参数长度必须完全匹配 if (paramTypes.length != explicitArgs.length) { continue; } // 根据参数创建参数持有者 argsHolder = new ArgumentsHolder(explicitArgs); } else { // 未提供参数,解析构造参数 try { String[] paramNames = null; // 获取 ParameterNameDiscoverer 对象 // ParameterNameDiscoverer 是用于解析方法和构造函数的参数名称的接口,为参数名称探测器 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { // 获取指定构造函数的参数名称 paramNames = pnd.getParameterNames(candidate); } // 在已经解析的构造函数参数值的情况下,创建一个参数持有者对象 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring, candidates.length == 1); } 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; } } // isLenientConstructorResolution 判断解析构造函数的时候是否以宽松模式还是严格模式 默认宽松模式 // 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常 // 宽松模式:使用具有"最接近的模式"进行匹配 // typeDiffWeight:类型差异权重 int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // 代表最接近的类型匹配,则选择作为构造函数 if (typeDiffWeight < minTypeDiffWeight) { factoryMethodToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousFactoryMethods = null; } // 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项 // 但是,仅在非宽松构造函数解析模式下执行该检查,并显式忽略重写方法(具有相同的参数签名) else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight && !mbd.isLenientConstructorResolution() && paramTypes.length == factoryMethodToUse.getParameterCount() && !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) { // 查找到多个可匹配的方法 if (ambiguousFactoryMethods == null) { ambiguousFactoryMethods = new LinkedHashSet<>(); ambiguousFactoryMethods.add(factoryMethodToUse); } ambiguousFactoryMethods.add(candidate); } } } // 没有可执行的工厂方法,抛出异常 if (factoryMethodToUse == null) { if (causes != null) { UnsatisfiedDependencyException ex = causes.removeLast(); for (Exception cause : causes) { this.beanFactory.onSuppressedException(cause); } throw ex; } List<String> argTypes = new ArrayList<>(minNrOfArgs); if (explicitArgs != null) { for (Object arg : explicitArgs) { argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null"); } } else if (resolvedValues != null) { Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount()); valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values()); valueHolders.addAll(resolvedValues.getGenericArgumentValues()); for (ValueHolder value : valueHolders) { String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) : (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null")); argTypes.add(argType); } } String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes); throw new BeanCreationException(mbd.getResourceDescription(), beanName, "No matching factory method found: " + (mbd.getFactoryBeanName() != null ? "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") + "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " + "Check that a method with the specified name " + (minNrOfArgs > 0 ? "and arguments " : "") + "exists and that it is " + (isStatic ? "static" : "non-static") + "."); } //返回类型不能为void else if (void.class == factoryMethodToUse.getReturnType()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid factory method '" + mbd.getFactoryMethodName() + "': needs to have a non-void return type!"); } //存在含糊的两个工厂方法,不知选哪个 else if (ambiguousFactoryMethods != null) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Ambiguous factory method matches found in bean '" + beanName + "' " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousFactoryMethods); } if (explicitArgs == null && argsHolderToUse != null) { mbd.factoryMethodToIntrospect = factoryMethodToUse; argsHolderToUse.storeCache(mbd, factoryMethodToUse); } } Assert.state(argsToUse != null, "Unresolved factory method arguments"); // 实例化 并返回 bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse)); return bw; } 

2.1 方法流程图

121_9.pnginstantiateUsingFactoryMethod

2.2 方法分析

  首先这个方法的流程比较长,首先声明:关于「推断构造函数」,这里暂时不做太多的分析,因为这一部分在后面的文章中通过构造函数实力化对象会详细介绍。

  这里为了让文章有头有尾,同样也为了读文章的时候不懵圈,我试着在这里将流程简要的串一下:

  • ①:首先就是 @Bean 方法对应的 BeanName是什么? BeanDefinition 是什么?

    beanName 就是对应的方法名称,BeanDefinition 就是 ConfigurationClassBeanDefinition

  • ②:然后就是在容器初始化的时候, @Bean 方法生成的 BeanDefinition 是如何解析的?怎么放到 BeanDefinitionMap 中去的?

    BeanDefinition 的定位加载注册,方法的入口是 loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)

  • ③:什么时候触发 getBean()?

    容器初始化的时候,在 refresh() 方法中的 finishBeanFactoryInitialization(beanFactory); 这里要注意在调用到 doGetBean(name, null, null, false)argsnull 在实例化的对象的时候用到。

  • ④:如何 getBean()

    for 循环容器中缓存的所有的 beanName 然后 getBean(beanName)

  • ⑤:第五步就是 这篇文章介绍的内容了: 「如何通过工厂方法完成Bean的实例化」
    • 5.1 实例化初始化 BeanWrapperImpl对象

      这个对象及其重要,后面的依赖注入就是通过这个对象来完成的

    • 5.2 通过 mbd.getFactoryBeanName()获取 factoryBeanName 通过 factoryBeanName 来区分 「静态」「非静态」@Bean方法,并做相应处理。
    • 5.3 确定参数,确定构造方法
    • 5.4 异常情况的判断及处理
    • 5.5 实例化对象

  上述的后 5.2 ~ 5.5的部分就是 instantiateUsingFactoryMethod()方法的重点,这里不在赘述。至此 @Bean方法的对象的实例化过程已经分析完了。最后,如有什么问题,还希望各位斧正。恕在下之言,这篇文章可累死老夫了…需要原图的话,想办法私聊我吧。

本文使用 mdnice 排版

文章永久链接:https://tech.souyunku.com/28061

未经允许不得转载:搜云库技术团队 » 分析一波Spring中factory-method如何实例化对象的?

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们