createBean()是创建Bean的关键方法

一、createBean() 代码:

//AbstractAutowireCapableBeanFactory.java
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isDebugEnabled()) {logger.debug("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.//判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.//校验和准备Bean中的方法覆盖try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.//如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {//创建Bean的入口Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isDebugEnabled()) {logger.debug("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException ex) {// A previously detected exception with proper bean creation context already...throw ex;}catch (ImplicitlyAppearedSingletonException ex) {// An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

这段代码分为以下几个步骤:

1.判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载
2.校验和准备Bean中的方法注入
3.如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象
4.创建Bean

  • 第1步:主要是获取bean的class,并设置到BeanDefinition中
  • 第2步:主要是处理方法注入
    代码:
public void prepareMethodOverrides() throws BeanDefinitionValidationException {// Check that lookup methods exists.//检测是否存在方法注入,并循环预处理方法注入if (hasMethodOverrides()) {Set<MethodOverride> overrides = getMethodOverrides().getOverrides();synchronized (overrides) {//遍历处理for (MethodOverride mo : overrides) {prepareMethodOverride(mo);}}}}

prepareMethodOverride(mo):

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {// 统计注入的方法个数   int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());if (count == 0) {throw new BeanDefinitionValidationException("Invalid method override: no method with name '" + mo.getMethodName() +"' on class [" + getBeanClassName() + "]");}// 如果为1,则将注入方法标记为未重载// 注意:当有多个重载方法时,为了确定调用哪个具体的方法,Spring对重载方法的参数解析是很复杂的// 所以,如果注入方法没有被重载这里就将其标记,省去了对方法参数的解析过程,直接调用即可else if (count == 1) {// Mark override as not overloaded, to avoid the overhead of arg type checking.mo.setOverloaded(false);}}

代码读到这里,大家可能有疑问,从代码上看明明是处理的方法重载,但是为什么处理的是方法注入呢?而且如果我们在bean里设置几个方法重载的话,hasMethodOverrides()方法返回的是false。如果我们打开 AbstractBeanDefinition 类的 hasMethodOverrides() 方法,就能打消我们之前的疑问。

public boolean hasMethodOverrides() {return (this.methodOverrides != null && !this.methodOverrides.isEmpty());}

其中methodOverrides是做什么的呢?通过类名AbstractBeanDefinition我们可以发现,该类是BeanDefinition的一个子类,那么它保存的应该是我们解析到的beanDefinition,spring在解析配置文件的时候,如果发现配置了replace-method或者lookup-method那么,就会对应的标签解析,并存入到 AbstractBeanDefinitionmethodOverrides 属性中,那么当bean实例化的时候,如果检测到了methodOverrides属性不为空,则动态的为当前bean生成代理并使用相应的拦截器对bean做处理,这里大家只要把概念搞清楚即可。

  • 第3步
    主要是对bean前置后置处理器的处理,给 BeanPostProcessors 后置处理器一个返回代理对象的机会

详细代码:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}

如果代理对象不为空,则直接返回代理对象,这一步骤有非常重要的作用,Spring 后续实现 AOP 就是基于这个地方判断的。

这个方法核心就在于 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization() 两个方法,before 为实例化前的后处理器应用,after 为实例化后的后处理器应用。

  • 第4步
    doCreateBean()

创建Bean

//真正创建Bean的方法protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.//BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {//单例模式,删除factoryBean缓存instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//使用合适的实例化策略来创建Bean:工厂方法、构造函数自动注入、简单初始化instanceWrapper = createBeanInstance(beanName, mbd, args);}//从包装类中获取实例化的Beanfinal Object bean = instanceWrapper.getWrappedInstance();//获取实例化对象的类型Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.//检查是否有后置处理synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {//调用PostProcessor后置处理器,修改 BeanDefinitionapplyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.// 解决单例模式的循环依赖boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.//Bean对象的初始化,依赖注入在此触发//这个exposedObject在初始化完成之后返回作为依赖注入完成后的BeanObject exposedObject = bean;try {//将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象populateBean(beanName, mbd, instanceWrapper);//初始化Bean对象exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {//获取指定名称的已注册的单例模式Bean对象Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {//根据名称获取的已注册的Bean和正在实例化的Bean是同一个if (exposedObject == bean) {//当前实例化的Bean初始化完成exposedObject = earlySingletonReference;}//当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);//获取当前Bean所依赖的其他Beanfor (String dependentBean : dependentBeans) {//对依赖Bean进行类型检查if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.//注册完成依赖注入的Beantry {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}

代码很长,不过别慌,我们来按步骤分析一波

1.如果是单例模式,从factoryBeanInstanceCache 缓存中获取BeanWrapper 实例对象并删除缓存
2.调用createBeanInstance() 实例化 beanundefined(主要是将 BeanDefinition 转换为BeanWrapper)
3.后置处理
4.单例模式的循环依赖处理
5.初始化 bean 实例对象undefined(属性填充)
6.依赖检查
7.注册DisposableBean

doCreateBean() 完成 bean 的创建和初始化工作,内容太多,比较复杂,这里只列出大致流程。

本文转自:https://cloud.tencent.com/developer/article/1503301

Spring Ioc 之 Bean的加载(3):createBean()相关推荐

  1. Spring Ioc 之 Bean的加载(1)(生命周期)

    在之前的文章中,我们分析了Spring的Ioc的初始化过程,实际上就是把 beanName 和 BeanDefinition 注册到DefaultListableBeanFactory的map中. 在 ...

  2. Spring源码——bean的加载

    前言 内容主要参考自<Spring源码深度解析>一书,算是读书笔记或是原书的补充.进入正文后可能会引来各种不适,毕竟阅读源码是件极其痛苦的事情. 本文主要涉及书中第五章的部分,依照书中内容 ...

  3. Spring : Bean延时加载注解(@Lazy)

    1.美图 2.概述 @Lazy:用于标识Bean是否需要延迟加载,延时加载就是在第一次使用的时候才加载.@Lazy的主要作用就是用来减少Spring IOC容器启动的加载时间. 3.源码 @Targe ...

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

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

  5. Spring Bean懒加载与非懒加载

    懒加载:对象使用的时候才去创建.节省资源,但是不利于提前发现错误: 提前加载:容器启动时立马创建.消耗资源,但有利于提前发现错误 Spring 默认设置是非懒加载 1,由于在controller中会注 ...

  6. Spring 源码分析(七)--bean的加载详细分析

    一:缓存中获取单例bean 前面已经提到过,单例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试从sing ...

  7. 《Spring源码深度解析 郝佳 第2版》bean的加载、循环依赖的解决

    往期博客: <Spring源码深度解析 郝佳 第2版>容器的基本实现与XML文件的加载 <Spring源码深度解析 郝佳 第2版>XML标签的解析 往期博客完成了xml文件加载 ...

  8. Spring 源码解析(四):bean的加载

    //spring.xml 文件解析BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring.xml&quo ...

  9. Spring IOC容器-Bean管理——基于XML方式

    Spring IOC容器-Bean管理--基于XML(续集) 1.IOC 操作 Bean 管理(FactoryBean) ​ 1).Spring 有两种类型 bean,一种普通 bean,另外一种工厂 ...

最新文章

  1. VTK:PolyData之TransformOrderDemo
  2. Getting the right Exception Context from a Memory dump Fixed
  3. python treeview底部加个按钮_Python爬取京东商品信息(GUI版本)
  4. datastage 重启 续
  5. python的collection系列-默认字典(defaultdict)
  6. 【离散数学】基础理论归纳
  7. [译] 通过官网 Go 语言学习笔记 | How to Write Go Code
  8. iOS-调用系统的短信和发送邮件功能,实现短信分享邮件分享
  9. 黑白或彩色线稿地图设计定制装饰画中线条轮廓素材底图获取方法合集
  10. 网页中嵌入网易云音乐播放器
  11. Java混元功法_[转载]太乙混元功简介
  12. windows下如何使用配置七牛qshell命令工具
  13. 乐影音下载器 建议回复
  14. Python 语言发展历史
  15. 复选框判断是否选中及获取值
  16. 编写自己的聊天网站(一)
  17. 数制和码制(数制的转换的方法,BCD码<8421,2421,5421,余三码>,格雷码,原码,反码,补码,定点数和浮点数)
  18. 2021届前端面试知识点(其他)
  19. ubuntu下使用 RabbitVCSRapidSVN
  20. Unity3D 个人尝试经验总结

热门文章

  1. 什么是前后端分离 前后端不分离
  2. JBPM学习(六):详解流程图
  3. 【转载】C++操作符
  4. Surviving the Release Version
  5. Sql Server通用分页存储过程
  6. 关于asp.net2.0资源文件本地化多语言版本的一些小技巧
  7. this指针用法详解
  8. Matlab去掉数组中0
  9. 科大星云诗社动态20211130
  10. [:zh]<界面编程>任务二 用户注册界面设计[:]2018-01-24