目录

  • 前言
  • `initializeBean()` 方法概览
  • `initializeBean()` 方法详解
    • `invokeAwareMethods()` 方法
    • `applyBeanPostProcessorsBeforeInitialization()` 方法(重点)
    • `invokeInitMethods()` 方法(重点)
    • `applyBeanPostProcessorsAfterInitialization()` 方法(重点)
  • `spring` 中初始化 `bean` 的方式
    • 使用 `@PostConstruct` 注解
    • 实现 `InitializingBean` 接口
    • 使用 `@Bean` 注解
    • 执行顺序

前言

这篇文章是 IOC 容器初始化启动时,抽象类 AbstractAutowireCapableBeanFactorydoCreateBean() 方法里面的 initializeBean() 方法,它是进行 bean 的初始化的方法

阅读本篇文章,同时可以参考阅读 spring源码之getBean(获取 bean)方法解读(二) 和 Spring Aop代理对象的产生(一) 这两篇文章的 doCreateBean() 方法

initializeBean() 方法概览

到此时,bean 已完成了如下两个重要工作

  • 调用 createBeanInstance() 方法:完成 bean 的实例化工作
  • 调用 populateBean() 方法:完成 bean 的属性填充注入工作
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 对特殊的bean进行处理:实现了 Aware、BeanClassLoaderAware、BeanFactoryAware 的处理if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {// 激活 Aware 方法invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 调用了bean后处理器的方法// BeanPostProcessor 提供的方法,在bean初始化前调用,这时的 bean已完成了实例化和属性填充注入工作wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 激活自定义的init的方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// 调用bean后处理器的方法// BeanPostProcessor 提供的方法,在bean初始化后调用,这时候的bean 已经创建完成了wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}
  • 对实现了 Aware 接口的 bean 进行相关设置
  • 调用 bean 后处理器的方法 applyBeanPostProcessorsBeforeInitialization()
  • 执行实现了 InitializingBean 或者用户自定义的 init 方法方法
  • 调用 bean 后处理器的方法 applyBeanPostProcessorsAfterInitialization():此处可以产生 aop 的代理对象

initializeBean() 方法详解

invokeAwareMethods() 方法

实现 Aware 接口用于让 bean 能拥有某些额外的感知能力

  • 如果 bean 实现了 BeanNameAware 接口,则将 beanName 设置进去
  • 如果 bean 实现了 BeanClassLoaderAware 接口,则将 ClassLoader 设置进去
  • 如果 bean 实现了 BeanFactoryAware 接口,则将 beanFactory 设置进去
private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}

applyBeanPostProcessorsBeforeInitialization() 方法(重点)

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 获取所有实现了 BeanPostProcessors 接口的类,进行遍历for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {// 核心方法:postProcessBeforeInitialization()Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}

postProcessBeforeInitialization() 方法是 BeanPostProcessor 接口提供的方法,可以看到它是在 bean 初始化之前调用的,这时的 bean 已完成了实例化和属性填充注入工作

public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
  • postProcessBeforeInitialization():在 bean 初始化之前调用,可以改变 bean 的一些属性
  • postProcessAfterInitialization():在 bean 初始化之后调用,可以改变 bean 的一些属性

关于 BeanPostProcessor 接口的详解可以查看:https://blog.csdn.net/qq_36882793/article/details/106040809

关于 BeanPostProcessor 接口的详细使用可以查看:https://blog.csdn.net/mamamalululu00000000/article/details/106547490

invokeInitMethods() 方法(重点)

bean 的初始化方式除了可以使用 init-method 属性或 @Bean(initMethod=''”),还可以通过实现 InitializingBean 接口,并且在 afterPropertiesSet() 方法中实现自己初始化的业务逻辑

调用顺序则是 afterPropertiesSet() 先调用,后面调用 init-method 指定的方法

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {// 首先检查是否是InitializingBean,如果是的话则需要调用 afterPropertiesSet 方法boolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isDebugEnabled()) {logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}// 调用 afterPropertiesSet  方法if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {// 从RootBeanDefinition 中获取initMethod 方法名称String initMethodName = mbd.getInitMethodName();// 调用initMethod 方法if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {invokeCustomInitMethod(beanName, bean, mbd);}}
}

applyBeanPostProcessorsAfterInitialization() 方法(重点)

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;// 获取所有实现了 BeanPostProcessors 接口的类,进行遍历for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {// 核心方法:postProcessAfterInitialization()Object current = beanProcessor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}

postProcessAfterInitialization() 方法是 BeanPostProcessor 接口提供的方法,可以看到它是在 bean 初始化之后调用的,这时的 bean 已完成了实例化,属性填充注入,初始化的工作;可以认为是一个完整的 bean 已在 spring 容器中了

如果使用了 spring aop 功能,那么代理对象的产生就在这个 applyBeanPostProcessorsAfterInitialization() 方法中。注意产生代理对象的时机

  • 是在 bean 的实例化 createBeanInstance() 方法,属性填充注入populateBean() 方法之后的 initializeBean() 初始化方法中产生的
  • initializeBean() 方法中的applyBeanPostProcessorsAfterInitialization() 方法具体产生

spring 中初始化 bean 的方式

  • xml 配置文件中指定 init-method 标签
  • 使用 @PostConstruct 注解
  • 实现 InitializingBean 接口
  • 使用 @Bean 注解

使用 @PostConstruct 注解

@Service
public class AService {@PostConstructpublic void init() {System.out.println("===初始化===");}
}

实现 InitializingBean 接口

@Service
public class BService implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("===初始化===");}
}

使用 @Bean 注解

使用 initMethod() 可以指定初始化方法

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {@AliasFor("name")String[] value() default {};@AliasFor("value")String[] name() default {};Autowire autowire() default Autowire.NO;String initMethod() default "";String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}

执行顺序

具体的执行顺序可以查看 initializeBean() 源码

Spring源码之bean的初始化initializeBean方法解读相关推荐

  1. Spring-bean的循环依赖以及解决方式___Spring源码初探--Bean的初始化-循环依赖的解决

    本文主要是分析Spring bean的循环依赖,以及Spring的解决方式. 通过这种解决方式,我们可以应用在我们实际开发项目中. 什么是循环依赖? 怎么检测循环依赖 Spring怎么解决循环依赖 S ...

  2. Spring源码解析-bean实例化

    Spring源码解析-bean实例化 ​ 本文介绍Spring创建 bean 过程中的第一个步骤:实例化 bean. 1. Bean实例化源码 ​ 虽然实例化Bean有多种方式(包括静态工厂和工厂实例 ...

  3. Spring 源码解析 - Bean创建过程 以及 解决循环依赖

    一.Spring Bean创建过程以及循环依赖 上篇文章对 Spring Bean资源的加载注册过程进行了源码梳理和解析,我们可以得到结论,资源文件中的 bean 定义信息,被组装成了 BeanDef ...

  4. Spring源码深度解析,Spring源码以及Bean的生命周期(五)(附代码示例:)

    五)Bean 的生命周期,创建---初始化---销毁的过程 目录 五)Bean 的生命周期,创建---初始化---销毁的过程 一 ,  指定初始化方法 init-method 方法​ 二 ,指定销毁 ...

  5. Spring源码剖析——Bean的配置与启动

    IOC介绍   相信大多数人在学习Spring时 IOC 和 Bean 算得上是最常听到的两个名词,IOC在学习Spring当中出现频率如此之高必然有其原因.如果我们做一个比喻的话,把Bean说成Sp ...

  6. Spring源码之Bean的注册(使用XML配置的方式)

    本文分析的Spring源码是5.2.2版本,使用Gradle进行管理. 一.Bean的注册,先来看通过XML配置Bean的方式 1.配置applicationContext.xml: <?xml ...

  7. 一、如何阅读Spring源码(全网最简单的方法)

    学习Java最好最有效的方法是学习Spring,但是最笨最没效的方法也是学习Spring. 为什么这么说呢?道理其实很简单 A.Spring很庞大,很完善,也非常的底层,如果我们学会的Spring,那 ...

  8. Spring源码分析——Bean的生命周期

    文章目录 说明 测试代码 说明 本文从源码的角度分析Spring中Bean的加载过程,本文使用的Spring版本为4.3.25.RELEASE 测试代码 测试代码如下,根据这段简单的测试代码,一步步跟 ...

  9. Spring源码之Bean的注册(注解方式)

    1.创建AnnotationConfigApplicationContext AnnotationConfigApplicationContext context = new AnnotationCo ...

  10. 三 spring源码解析--- Bean解析接口结构分析

    2019独角兽企业重金招聘Python工程师标准>>> 解析Bean是通过定义抽象的bean reader来解析,结构图如下 1.AbstractBeanDefinitionRead ...

最新文章

  1. 百信银行基于 Apache Hudi 实时数据湖演进方案
  2. Kotlin入门简介
  3. 方程组的直接解法和迭代法 python_最小二乘法及python 实现
  4. 微信授权 php josn,php怎么获取微信多客服json数据
  5. 42岁失业,有150万存款,房子无贷款,不想上班做点什么好?
  6. (Windows7)Visual Studio 2017编译运行出现脚本错误的解决方法
  7. Ubuntu 安装mujoco
  8. PPT计算机辅助教学,计算机辅助教学与多媒体课件制作
  9. T-SQL 基础简介
  10. python列表姓氏_Python 批量生成中文姓名(百家姓)
  11. pixi 小游戏_学习如何用pixi.js开发微信小游戏
  12. python生成摸头GIF动态图
  13. 练习二:工作日天气预报
  14. Unit3D打包android时出错 CommandInvokationFailure: Unable to list target platforms. Please make sure the a
  15. Hive基础知识及底层架构
  16. app 的 icon图标 有黑边
  17. 盘点系列:一度大热的TWS耳机今年表现如何?
  18. 惠州学院计算机学院2019,2019惠州学院专业排名
  19. 计算机桌面打标签,桌面记事本,详细教您怎么在桌面添加便签
  20. matlab求解代数等式,2008-2009学年线性代数试卷A及答案

热门文章

  1. 自动驾驶 11-2: 激光雷达传感器模型和点云 LIDAR Sensor Models and Point Clouds
  2. 算法:求树的最大深度104. Maximum Depth of Binary Tree
  3. AWS SageMaker 基于 XGBoost 的用户流失预测
  4. linux内核代码入口地址,Linux内核源代码分析——Linux内核的入口
  5. 新浪推荐 二面 移动零
  6. 第五章平稳过程(1)
  7. 怎么回滚版本_Win 10 暂停更新及回滚方法
  8. vofuria的开发(3)将vuforia引入新建立的工程
  9. css中margin标记可以带一个、二个、三个、四个参数,各有不同的含义
  10. 【2019 NWERC - D 】Disposable Switches【最短路、单调栈、数学思维】