Spring IOC - Bean的初始化

news/2024/12/2 17:56:11/

        在bean的初始化阶段,bean已经被实例化及属性填充了,此时的bean已相对成熟,接下来的初始化阶段还会做一些额外的工作对bean做进一步处理,主要包括以下四个方面:

  1. 调用aware接口方法

  2. 初始化前:调用初始化前的后置处理器方法

  3. 初始化:调用InitializingBean接口的afterPropertiesSet方法

  4. 初始化后:调用初始化后的后置处理器方法

1. Bean初始化主流程

        AbstractAutowireCapableBeanFactory#initializeBean

        运用aware回调接口、afterPropertiesSet方法、后置处理器完成bean实例的初始化

// 运用aware回调接口、afterPropertiesSet方法、后置处理器完成bean实例的初始化
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {// 1.调用aware接口的方法invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 2.调用初始化前后置处理器wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 3.调用初始化方法,其实就是afterPropertiesSet方法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()) {// 4.调用初始化后后置处理器wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}

2. Aware接口调用

        如果Bean实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口,则会调用相应接口的方法。

  • BeanNameAware:在Bean实例化后进行扩展操作,可以获取Bean的名称
  • BeanClassLoaderAware:在Bean实例化后进行扩展操作,可以获取Bean的类加载器
  • BeanFactoryAware:在Bean实例化后进行扩展操作,可以获取Bean所属的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);}}
}

3. 初始化前:调用初始化前的后置处理器方法

        这里涉及到了Bean后置处理器:BeanPostProcessor,其作用如下:

  1. spring会自动从它的所有的bean定义中检测BeanPostProcessor类型的bean定义,然后实例化它们,再将它们应用于随后创建的每一个bean实例

  2. 在bean实例的初始化方法回调之前调用BeanPostProcessor的postProcessBeforeInitialization的方法

  3. 在bean实例的初始化方法回调之后调用BeanPostProcessor的postProcessAfterInitialization的方法

  4. 通常,通过标记接口等方式填充bean的后置处理器会实现postProcessBeforeInitialization方法,而将bean包装为代理的后置处理器会实现postProcessAfterInitialization方法

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;}
}
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessBeforeInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}

        例如ApplicationContextAwareProcessor后置处理器,其重写了postProcessBeforeInitialization方法,如果bean实现了EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware接口,则会调用响应接口的方法

  • EnvironmentAware:在Bean实例化后进行扩展操作,可以获取Environment实例
  • EmbeddedValueResolverAware:在Bean实例化后进行扩展操作,可以获取StringValueResolver实例,可用于解析占位符
  • ResourceLoaderAware:在Bean实例化后进行扩展操作,可以获取ResourceLoader实例
  • ApplicationEventPublisherAware:在Bean实例化后进行扩展操作,可以获取ApplicationEventPublisher实例
  • MessageSourceAware:在Bean实例化后进行扩展操作,可以获取MessageSource实例
  • ApplicationContextAware:在Bean实例化后进行扩展操作,可以获取ApplicationContext实例

4. 初始化:调用InitializingBean接口的afterPropertiesSet方法或自定义的init方法

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {boolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isTraceEnabled()) {logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {// 调用afterPropertiesSet方法((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {// 调用自定义的init方法invokeCustomInitMethod(beanName, bean, mbd);}}
}

5. 初始化后:调用初始化后的后置处理器方法

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}

http://www.ppmy.cn/news/79481.html

相关文章

人人都能看懂的Spring源码解析,Spring声明式事务关于传播特性、事务挂起与恢复的处理

人人都能看懂的Spring源码解析&#xff0c;Spring声明式事务关于传播特性、事务挂起与恢复的处理 原理解析AbstractPlatformTransactionManager事务传播特性事务挂起与恢复通过DataSourceTransactionManager看事务挂起和恢复的具体实现 代码走读总结 往期文章&#xff1a; 人人…

【图像处理】CCL算法--二值图的连通域提取

https://en.wikipedia.org/wiki/Connected-component_labeling 目录 一、说明 二、连通性是拓扑模型 2.1 拓扑连通定义 2.2 道路连通

Java中的阻塞队列

什么是阻塞队列 阻塞队列&#xff08;BlockingQueue&#xff09;是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除方法。 附加操作解释支持阻塞的插入方法意思是当队列满时&#xff0c;队列会阻塞插入元素的线程&#xff0c;直到队列不满。支持阻塞的移除…

由浅入深Dubbo网络通信深入解析

目录 1 dubbo中数据格式2 消费方发送请求3 提供方接收请求4 提供方返回调用结果5 消费方接收调用结果6 异步转同步7 异步多线程数据一致8 心跳检查 1 dubbo中数据格式 解决socket中数据粘包拆包问题&#xff0c;一般有三种方式 定长协议&#xff08;数据包长度一致&#xff09…

PAT A1084 Broken Keyboard

1084 Broken Keyboard 分数 20 作者 CHEN, Yue 单位 浙江大学 On a broken keyboard, some of the keys are worn out. So when you type some sentences, the characters corresponding to those keys will not appear on screen. Now given a string that you are suppo…

Edgedetect2

边缘检测&#xff0c;检查数据变化&#xff0c;用异或实现 对于 8 位矢量中的每个位&#xff0c;检测输入信号何时从一个时钟周期变为下一个时钟周期&#xff08;检测任何边沿&#xff09;。输出位应在发生 0 到 1 转换后设置周期。 以下是一些示例。为清楚起见&#xff0c;in…

多线程 线程池任务队列

runnableTaskQueue&#xff08;任务队列&#xff09;&#xff1a;用于保存等待执行的任务的 阻塞队列 。可以选择以下几个阻塞队列。 阻塞队列解释补充ArrayBlockingQueue一个由数组结构组成的有界阻塞队列FIFO创建一个公平的阻塞队列ArrayBlockingQueue fairQueue new Array…

亚马逊云科技宣布全面推出Amazon Aurora I/O-Optimized集群配置

自亚马逊云科技Amazon Aurora于2014年推出以来&#xff0c;成千上万的客户选择Aurora来运行其要求最严苛的应用程序。Aurora在全球范围内提供无与伦比的高性能和可用性&#xff0c;完全兼容MySQL和PostgreSQL&#xff0c;成本仅为商用数据库的十分之一。 许多亚马逊云科技客户受…