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

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

1.回顾

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

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

  最后转化成相应的 BeanDefinition 注册到 BeanDefinitionMap 中去: @Bean之对象注册编辑器

  首先咱们其中一个 BeanDefinition 为例,从上图中查看这个 BeanDefinition 中都包含哪些信息。 @Bean注解注册的BDide

  这里看到,将 BeanDefinition 注册到 Map 中去了,可是这里这个注册并非这么简单的。这里要对一下几种状况加以区分,要否则看到后面的 instantiateUsingFactoryMethod() 方法确定会懵圈的。下面咱们紧接着来分析分析 @Bean的处理情形...函数

  验证几种情形的须要的类:flex

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();  } } 复制代码
situation_01
situation_01

1.2 非静态的构造方法

@Configuration
@ComponentScan("com.demo") public class DemoConfigOne {   @Bean  public FactoryBeanDemoOne demoFactoryBean() {  return new FactoryBeanDemoOne();  } } 复制代码
situation_02
situation_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();  }  } 复制代码
situation_03
situation_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();  }  } 复制代码
situation_04
situation_04

2.经过工厂方法建立实例

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

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 方法流程图

instantiateUsingFactoryMethod
instantiateUsingFactoryMethod

2.2 方法分析

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

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

  • ①:首先就是 @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 排版

相关文章
相关标签/搜索