前言

  • spring创建bean的方式
  • 测试代码准备
  • createBeanInstance()方法分析
    • instantiateUsingFactoryMethod()方法分析
  • 总结

spring创建bean的方式

  1. 构造方法

    1. 无参构造方法
    2. 有参构造方法
  2. 工厂方法

    1. 静态工厂方法
    2. 实例工厂方法
  3. 实现FactoryBean接口

    前两篇《Spring源码分析系列——bean创建过程分析(一)——默认无参构造方法创建bean》和《Spring源码分析系列——bean创建过程分析(二)——有参构造方法创建bean》介绍了构造方法创建bean的主要流程,本篇分析一下工厂方式创建bean,包括静态工厂和实例工厂方式

测试代码准备

xml配置如下

<bean id="boyService" class="yxf.instantiate.InstantiateFactory" factory-method="getBoyFromStaticFactoryMethod" ><!--<property name="friend" ref="grilService"></property>-->
</bean>
<bean id="instantiateFactory" class="yxf.instantiate.InstantiateFactory" />

实体类代码

public class Lad implements Boy {private String name;private Gril friend;private Money money;public Lad(String name) {this.name = name;}
}public class MagicGril implements Gril {private String name;private Boy friend;public MagicGril(){}public MagicGril(String name) {this.name = name;}
}

工厂方法代码

public class InstantiateFactory {public static Lad getBoyFromStaticFactoryMethod() {return new Lad("swk");}public MagicGril getGrilFromMemberFactoryMethod(String name) {return new MagicGril(name);}
}

运行测试代码

public class MyXmlConfig {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("/application.xml");Lad lad = (Lad) ac.getBean("boyService");System.out.println(lad);}
}

createBeanInstance()方法分析

基于之前的分析,创建单例bean的步骤都是经getBean、doGetBean、createBean、doCreateBean、createBeanInstance等步骤,本次直接从createBeanInstance方法开始分析

代码精简后

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.Class<?> beanClass = resolveBeanClass(mbd, beanName);if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());}Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}
}

很直观的,如果bean定义中有factoryMethodName,则直接走工厂方式创建bean。

instantiateUsingFactoryMethod()方法分析

protected BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);}

跟有参构造方法创建的autowireConstructor()方法一样,都是委托给ConstructorResolver类处理,看一下它的instantiateUsingFactoryMethod()方法。
精简之后

public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {BeanWrapperImpl bw = new BeanWrapperImpl();this.beanFactory.initBeanWrapper(bw);Object factoryBean;Class<?> factoryClass;boolean isStatic;//工厂bean名称String factoryBeanName = mbd.getFactoryBeanName();//如果有工厂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工厂中获取factoryBean实例factoryBean = this.beanFactory.getBean(factoryBeanName);if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {throw new ImplicitlyAppearedSingletonException();}factoryClass = factoryBean.getClass();isStatic = false;}//如果有工厂bean,则走实例工厂创建,没有则走静态工厂创建else {// It's a static factory method on the bean 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;}Method factoryMethodToUse = null;ArgumentsHolder argsHolderToUse = null;Object[] argsToUse = null;if (explicitArgs != null) {argsToUse = explicitArgs;}else {Object[] argsToResolve = null;//从缓存中找,第一次没有synchronized (mbd.constructorArgumentLock) {factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {// Found a cached factory method...argsToUse = mbd.resolvedConstructorArguments;if (argsToUse == null) {argsToResolve = mbd.preparedConstructorArguments;}}}if (argsToResolve != null) {argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);}}//决定是用哪个静态方法if (factoryMethodToUse == null || argsToUse == null) {// Need to determine the factory method...// Try all methods with this name to see if they match the given arguments.factoryClass = ClassUtils.getUserClass(factoryClass);List<Method> candidates = null;         if (candidates == null) {candidates = new ArrayList<>();//找到工厂类所有的方法Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);for (Method candidate : rawCandidates) {//找到静态的,并且是定义的工厂方法名的方法if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {candidates.add(candidate);}}}//如果只有一个符合的静态方法,并且没有指定构造方法参数if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {Method uniqueCandidate = candidates.get(0);//方法的形参数为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;}}//如果有多个候选方法,则需要排序if (candidates.size() > 1) {  // explicitly skip immutable singletonListcandidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);}ConstructorArgumentValues resolvedValues = null;boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);int minTypeDiffWeight = Integer.MAX_VALUE;Set<Method> ambiguousFactoryMethods = null;int minNrOfArgs;if (explicitArgs != null) {minNrOfArgs = explicitArgs.length;}else {//解析bean定义中定义的构造方法参数if (mbd.hasConstructorArgumentValues()) {ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();resolvedValues = new ConstructorArgumentValues();minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}else {minNrOfArgs = 0;}}LinkedList<UnsatisfiedDependencyException> causes = null;for (Method candidate : candidates) {int parameterCount = candidate.getParameterCount();if (parameterCount >= minNrOfArgs) {ArgumentsHolder argsHolder;Class<?>[] paramTypes = candidate.getParameterTypes();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);}//根据bean定义的参数,转换给工厂方法需要的参数argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);}catch (UnsatisfiedDependencyException ex) {}}int typeDiffWeight = (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));if (typeDiffWeight < minTypeDiffWeight) {factoryMethodToUse = candidate;argsHolderToUse = argsHolder;argsToUse = argsHolder.arguments;minTypeDiffWeight = typeDiffWeight;ambiguousFactoryMethods = null;}}}if (explicitArgs == null && argsHolderToUse != null) {mbd.factoryMethodToIntrospect = factoryMethodToUse;//将第一次找到的方法、及参数放入缓存,以备下次查找时直接从缓存中取argsHolderToUse.storeCache(mbd, factoryMethodToUse);}}//根据指定的工厂bean和指定的工厂方法或者找到的静态工厂方法创建beanbw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));return bw;

总结

工厂方法创建bean与构造方法创建bean大致步骤差不多,都是先确定方法和参数,然后反射创建bean。

Spring源码分析系列——bean创建过程分析(三)——工厂方法创建bean相关推荐

  1. 【四】Spring源码分析之启动主流程---AbstractApplicationContext的refresh方法

    入口: 在SpringBoot启动的时候,SpringApplication的run方法中 refreshContext(context); 里面最终调用的是AbstractApplicationCo ...

  2. Spring源码分析系列-Bean的生命周期(总结篇)

    ApplicationContext和BeanFactory   BeanFactory是Spring中的顶层接口,只负责管理bean,而ApplicationContext也实现了BeanFacto ...

  3. 【Spring源码分析系列】bean的加载

    前言 以 BeanFactory bf  = new XmlBeanFactory(new ClassPathResource("beans.xml"));为例查看bean的加载过 ...

  4. spring源码分析系列(一)

    本系列以官方开发文档+spring5的源码为主 一.IOC 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中 ...

  5. Spring源码分析系列-循环依赖和三级缓存

    目录 循环依赖 多级缓存 一级缓存 二级缓存 当循环依赖遇上AOP 三级缓存 Spring三级缓存源码实现 总结 循环依赖   BeanFactory作为bean工厂管理我们的单例bean,那么肯定需 ...

  6. spring源码分析系列(二)AOP应用

    这里讲AOP应用 先来说说一个比较虚无缥缈的问题:什么是AOP? 1.OOP 在说AOP之前,我们需要先看看什么是OOP:Object Oriented Programming,翻译过来就是面向对象编 ...

  7. Spring源码分析之BeanPostProcessor接口和BeanFactoryPostProcessor接口方法不执行原因分析

    首先下面是我的Bean /** Copyright 2002-2017 the original author or authors.** Licensed under the Apache Lice ...

  8. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  9. Spring IOC 容器源码分析系列文章导读

    1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...

最新文章

  1. Spark组件和术语定义
  2. JDBC批处理读取指定Excel中数据到Mysql关系型数据库
  3. cx_sy_dyn_call_illegal_type
  4. 【GCN】图卷积网络(GCN)入门详解
  5. Disruptor并发框架-1
  6. probe request帧结构_WLAN 无线网络 09 - 管理帧
  7. 计算机管理器win8,Win8如何快速打开资源管理器,Win8快速打开计算机操作方法
  8. C语言编程时没思路,c语言编程问题
  9. 危机十足站长的生命觉悟:拼命也得每天挤一滴墨水!
  10. Vue-cli 3.0+ 设置接口代理 设置vue.config.js的配置项
  11. fastjson safemode_Fastjson远程代码执行漏洞安全通告
  12. 输出结果 配置_用单端仪表放大器实现全差分输出
  13. Microsoft SQL Server 双机热备份,实时同步
  14. pe系统测试软件,使用PE系统显示器测试工具检测电脑屏幕的方法
  15. linux 内存管理(8) —内存描述符(mm_struct)
  16. 打开CMD的方式以及常用的指令
  17. 人工智能数学基础-内积和外积
  18. 6n137光耦怎么测好坏_817A光耦怎么测好坏,光耦合器
  19. python---flask
  20. 关于RC阻容复位电路的问题

热门文章

  1. SOLID原则 【转】
  2. 09——规范数据库设计
  3. 原来ChatGPT可以充当这么多角色
  4. Android - Windows 多样化投屏方案
  5. 解决warning C4305: 'initializing' : truncation from 'const double' to 'float'
  6. 戴尔 Inspiron灵越 14 7447(游匣7000)酷睿 i7 4代全新机回收价格
  7. 【蓝桥杯历年真题合集】蓝桥杯2020初赛
  8. 三菱PLC CCD控制ST程序 本PLC程序中CCD控制用的ST结构化语言,程序都有注释
  9. The Fun Of Algorithm - Day4 - 百钱百鸡问题
  10. MySQL中按天、自然周、月、季度、年份统计