一个 Bean 就这样走完了它的一生之 Bean 的出生

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
函数计算FC,每月15万CU 3个月
简介: 想了解 Spring 中 Bean 的销毁流程么?本文将从 Spring 源码的角度带你一步一步查看 Spring 中的 Bean 销毁时候生命周期的每个方法是如何被调用的。

## 生命周期流程

Spring 中的一个 Bean 从被创建到被销毁,需要经历很多个阶段的生命周期,下图是一个 Bean 从创建到销毁的生命周期流程:

![image.png](https://i-blog.csdnimg.cn/img_convert/e38825f2f05e29eb3b604ef31669f2bb.png)


在 Bean 的各个生命周期流程点,Spring 都提供了对应的接口或者注解,以便开发者在各个生命周期的流程点能够做一些自己的操作。


## 案例解析

### 定义 Spring 上下文工具类

Spring 中生命周期最常见的应用可能是定义一个 Spring 上下文的工具类。这个工具类也使用 `@Component` 注解修饰,表明**它也是一个 Bean** ,其次它实现了 `ApplicationContextAware` 接口,则说明它作为一个 Bean 被创建以及初始化的过程中需要调用 `setApplicationContext()` 方法,设置它所在的 Spring 上下文。代码如下:

```java

@Component

public class SpringContextUtils implements ApplicationContextAware {


   private static ApplicationContext applicationContext;


   /**

    * Spring会自动调用这个方法,注入ApplicationContext

    */

   @Override

   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

       SpringContextUtils.applicationContext = applicationContext;

   }


   /**

    * 获取ApplicationContext

    * @return ApplicationContext

    */

   public static ApplicationContext getApplicationContext() {

       if (applicationContext == null) {

           throw new IllegalStateException("ApplicationContext is not set. Make sure SpringContextUtils is properly initialized.");

       }

       return applicationContext;

   }


   /**

    * 通过名称获取Bean

    * @param name Bean的名称

    * @return Bean实例

    */

   public static Object getBean(String name) {

       return getApplicationContext().getBean(name);

   }


   /**

    * 通过名称和类型获取Bean

    * @param name Bean的名称

    * @param requiredType Bean的类型

    * @param <T> Bean的类型

    * @return Bean实例

    */

   public static <T> T getBean(String name, Class<T> requiredType) {

       return getApplicationContext().getBean(name, requiredType);

   }


   /**

    * 通过类型获取Bean

    * @param requiredType Bean的类型

    * @param <T> Bean的类型

    * @return Bean实例

    */

   public static <T> T getBean(Class<T> requiredType) {

       return getApplicationContext().getBean(requiredType);

   }

}

```

### 在 Bean 的依赖注入之后执行初始化操作

比如下面的案例中,`MyService` 这个 Bean 需要在它的依赖 `MyRepository` 这个 Bean 注入完成之后,调用依赖的 `loadInitialData()` 方法加载初始数据。代码如下:

```java

@Service

public class MyService {


   private MyRepository myRepository;

 

   private List<String> initialData;


   @Autowired

   public void setMyRepository(MyRepository myRepository) {

       this.myRepository = myRepository;

   }


   // 依赖注入完成后执行的初始化方法

   @PostConstruct

   public void init() {

       this.initialData = myRepository.loadInitialData();

   }


   public void doBusinessLogic() {

   }

}


@Service

class MyRepository {

   public List<String> loadInitialData() {

   }

}

```


`@PostConstruct` 注解是 JSR-250 标准定义的注解,它与 Spring 框架的耦合度比较低。除此之外还可以实现 `InitializingBean` 接口,在它的 `afterPropertiesSet()` 方法中来完成初始化;通过 XML 配置 `init-method` 或者 `@Bean` 注解的 `initMethod` 属性来指定任意的方法作为初始化方法来完成初始化。


## Bean 创建源码解析

在 Spring 源码实现中实际上分为了三个大的步骤:**实例化 -> 填充属性 -> 初始化**。填充属性可以看前面的文章[Spring 中@Autowired,@Resource,@Inject 注解实现原理](https://mp.weixin.qq.com/s/WVpWDU2JXFbpl-hgsywUXQ)。在上面生命周期图片中的从 `XXXAware` 的 `setXXXAware()` 方法到 `postProcessAfterInitialization()` 都属于初始化的这个步骤中。


在 `AbstractAutowireCapableBeanFactory` 中提供的 `doCreateBean()` 方法中提现了这三个大的步骤,其中的 `createBeanInstance()` 方法完成 Bean 的实例化;`populateBean()` 方法完成 Bean的属性填充;`initializeBean()` 方法完成 Bean 的初始化。代码如下:

```java

protected Object doCreateBean(String beanName, RootBeanDefinition mbd,

@Nullable Object[] args) throws BeanCreationException {

   // Instantiate the bean.  

   BeanWrapper instanceWrapper = null;  

 

   if (instanceWrapper == null) {  

      //实例化Bean

      instanceWrapper = createBeanInstance(beanName, mbd, args);  

   }  

   Object bean = instanceWrapper.getWrappedInstance();  

 

   // 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) {  

      addSingletonFactory(beanName,

       () -> getEarlyBeanReference(beanName, mbd, bean));  

   }  

 

   // Initialize the bean instance.  

   Object exposedObject = bean;  

   try {  

      //填充Bean的属性,比如处理@Autowired,@Resource,@Inject注解

      populateBean(beanName, mbd, instanceWrapper);  

   

      //初始化Bean

      exposedObject = initializeBean(beanName, exposedObject, mbd);  

   } catch {

   }

}

```

### initializeBean()方法流程

在 `initializeBean()` 方法中又分为:**调用 invokeAwareMethods() 方法 -> 调用 applyBeanPostProcessorsBeforeInitialization() 方法 -> 调用 invokeInitMethods() 方法 -> 调用 applyBeanPostProcessorsAfterInitialization() 方法**,代码如下:

```java

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {

     //调用Aware()方法

     invokeAwareMethods(beanName, bean);


     Object wrappedBean = bean;

     if (mbd == null || !mbd.isSynthetic()) {

         //调用BeanPostProcessor的postProcessBeforeInitialization()方法

         wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

     }


     try {

         //调用初始化方法

         invokeInitMethods(beanName, wrappedBean, mbd);

     }

     catch (Throwable ex) {

         throw new BeanCreationException(

                 (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);

     }

     if (mbd == null || !mbd.isSynthetic()) {

         //调用BeanPostProcessor的postProcessAfterInitialization()方法

         wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

     }


     return wrappedBean;

}

```


### invokeAwareMethods()方法流程

需要注意的是 `invokeAwareMethods()` 方法中仅仅只调用实现了 `BeanNameAware`,`BeanClassLoaderAware`,`BeanFactoryAware` 接口的方法。而常见的 `ApplicationContextAware` 接口的 `setApplicationContext()` 方法则是在 `ApplicationContextAwareProcessor` 的 `postProcessBeforeInitialization()` 方法中调用的。代码如下:

```java

public abstract class AbstractAutowireCapableBeanFactory {

   private void invokeAwareMethods(String beanName, Object bean) {

       if (bean instanceof Aware) {

           if (bean instanceof BeanNameAware beanNameAware) {

               //调用setBeanName()方法

               beanNameAware.setBeanName(beanName);

           }

           if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {

               ClassLoader bcl = getBeanClassLoader();

               if (bcl != null) {

                   //调用setBeanClassLoader()方法

                   beanClassLoaderAware.setBeanClassLoader(bcl);

               }

           }

           if (bean instanceof BeanFactoryAware beanFactoryAware) {

               //调用setBeanFactory()方法

               beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);

           }

       }

   }

}


class ApplicationContextAwareProcessor {

   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

       if (bean instanceof Aware) {

           this.invokeAwareInterfaces(bean);

       }


       return bean;

   }


   private void invokeAwareInterfaces(Object bean) {

       if (bean instanceof EnvironmentAware environmentAware) {

           environmentAware.setEnvironment(this.applicationContext.getEnvironment());

       }


       if (bean instanceof EmbeddedValueResolverAware embeddedValueResolverAware) {

           embeddedValueResolverAware.setEmbeddedValueResolver(this.embeddedValueResolver);

       }


       if (bean instanceof ResourceLoaderAware resourceLoaderAware) {

           resourceLoaderAware.setResourceLoader(this.applicationContext);

       }


       if (bean instanceof ApplicationEventPublisherAware applicationEventPublisherAware) {

           applicationEventPublisherAware.setApplicationEventPublisher(this.applicationContext);

       }


       if (bean instanceof MessageSourceAware messageSourceAware) {

           messageSourceAware.setMessageSource(this.applicationContext);

       }


       if (bean instanceof ApplicationStartupAware applicationStartupAware) {

           applicationStartupAware.setApplicationStartup(this.applicationContext.getApplicationStartup());

       }

     

       if (bean instanceof ApplicationContextAware applicationContextAware) {

           //这里调用的setApplicationContext()方法

           applicationContextAware.setApplicationContext(this.applicationContext);

       }


   }

}

```


### applyBeanPostProcessorsBeforeInitialization() 方法流程

在该方法中主要就是查找所有实现了 `BeanPostProcessor` 接口的对象,然后循环调用其 `postProcessBeforeInitialization()` 方法。代码如下:

```java

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;

}

```

在 Spring 中提供了 `CommonAnnotationBeanPostProcessor`(`@Resource` 注解也是它处理的) 实现了 `BeanPostProcessor` 接口,在它的构造函数里面初始化了要处理 `@PostConstruct` 注解。代码如下:

```java

public CommonAnnotationBeanPostProcessor() {

 setOrder(Ordered.LOWEST_PRECEDENCE - 3);


 // Jakarta EE 9 set of annotations in jakarta.annotation package

 addInitAnnotationType(loadAnnotationType("jakarta.annotation.PostConstruct"));

 addDestroyAnnotationType(loadAnnotationType("jakarta.annotation.PreDestroy"));


 // Tolerate legacy JSR-250 annotations in javax.annotation package

 addInitAnnotationType(loadAnnotationType("javax.annotation.PostConstruct"));

 addDestroyAnnotationType(loadAnnotationType("javax.annotation.PreDestroy"));

}

```


然后在它的子类 `InitDestroyAnnotationBeanPostProcessor` 的 `postProcessBeforeInitialization()` 实现了查找 `@PostConstruct` 注解修饰的方法,然后调用的逻辑。代码如下:

```java

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

   LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());

   try {

       metadata.invokeInitMethods(bean, beanName);

   }

   catch (InvocationTargetException ex) {

       throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());

   }

   catch (Throwable ex) {

       throw new BeanCreationException(beanName, "Failed to invoke init method", ex);

   }

   return bean;

}

```


### invokeInitMethods() 方法流程

在该方法中会先判断 Bean 是否实现了 `InitializingBean` 接口,如果实现了则调用其 `afterPropertiesSet()` 方法,然后查看 Bean 定义中是否有自定义的初始化方法,如果有的话,则调用自定义的初始化方法。代码如下:

```java

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)

   throws Throwable {

   boolean isInitializingBean = (bean instanceof InitializingBean);

   if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {

       if (logger.isTraceEnabled()) {

           logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");

       }

       //调用afterPropertiesSet()方法

       ((InitializingBean) bean).afterPropertiesSet();

   }


   if (mbd != null && bean.getClass() != NullBean.class) {

       String[] initMethodNames = mbd.getInitMethodNames();

       if (initMethodNames != null) {

           for (String initMethodName : initMethodNames) {

               if (StringUtils.hasLength(initMethodName) &&

                       !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&

                       !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {

                   //调用自定义初始化方法

                   invokeCustomInitMethod(beanName, bean, mbd, initMethodName);

               }

           }

       }

   }

}



protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd, String initMethodName)

   throws Throwable {

   Class<?> beanClass = bean.getClass();

   MethodDescriptor descriptor = MethodDescriptor.create(beanName, beanClass, initMethodName);

   String methodName = descriptor.methodName();


   Method initMethod = (mbd.isNonPublicAccessAllowed() ?

           BeanUtils.findMethod(descriptor.declaringClass(), methodName) :

           ClassUtils.getMethodIfAvailable(beanClass, methodName));

   //省略代码

 

   Method methodToInvoke = ClassUtils.getPubliclyAccessibleMethodIfPossible(initMethod, beanClass);


   try {

       ReflectionUtils.makeAccessible(methodToInvoke);

       //这里通过反射的方式调用初始化方法

       methodToInvoke.invoke(bean);

   }

   catch (InvocationTargetException ex) {

       throw ex.getTargetException();

   }

}

```


### applyBeanPostProcessorsBeforeInitialization() 方法流程

在该方法中主要就是查找所有实现了 `BeanPostProcessor` 接口的对象,然后循环调用其 `postProcessAfterInitialization()` 方法。代码如下:

```java

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

   LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());

   try {

       metadata.invokeInitMethods(bean, beanName);

   }

   catch (InvocationTargetException ex) {

       throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());

   }

   catch (Throwable ex) {

       throw new BeanCreationException(beanName, "Failed to invoke init method", ex);

   }

   return bean;

}

```

相关文章
|
15天前
|
人工智能 文字识别 安全
亚太唯一|阿里云实人认证获权威机构认可
构筑Deepfake下金融安全新防线
1438 64
|
3天前
|
定位技术 API
HarmonyOS实战:高德地图定位功能完整流程详解
本文详细介绍了在鸿蒙系统中使用高德地图实现完整定位功能的流程。首先分析需求,包括权限申请、检查GPS状态、单次或多次定位选择以及定位失败处理。接着通过代码实现具体步骤:添加定位权限、申请用户权限、检查GPS开关状态、启动定位服务,并处理定位成功或失败的情况。若定位失败,可尝试获取历史定位信息或使用默认位置。最后总结指出,虽然定位功能基础简单,但完整的流程与细节处理才是关键。建议读者动手实践,掌握高德地图定位功能的使用。
60 15
|
9天前
|
人工智能 自然语言处理 搜索推荐
我和灵码的故事——从AI编程小白到AI助手的伙伴
本文分享了一位非科班教师从零开始学习Python编程的经历,借助阿里云智能编码助手“灵码”,逐步尝试开发智能体以解决实际问题。作者通过灵码的实时代码续写、自然语言生成代码、单元测试生成等功能,克服了编程中的诸多困难,并成功为女儿打造了一个英语学习助手。文章还介绍了灵码在个性化学习支持和异常排查中的优势,以及如何用AI助力教育创新。无论你是编程初学者还是想构建自己的智能体,文中经验和技巧都值得借鉴。欢迎留言互动,一起探索AI世界的无限可能!
74 14
|
22天前
|
存储 人工智能 安全
MCP 规范新版本特性全景解析与落地实践
MCP Specification 在 2025-03-26 发布了最新的版本,本文对主要的改动进行详细介绍和解释
793 145
|
5天前
|
人工智能 监控 安全
MCP for 可观测2.0,6个让MCP开发更高效的小妙招
可观测近年来已经成为一个关键概念,它不仅仅局限于监控,还包括了日志记录、指标收集、分布式追踪等技术手段,旨在帮助团队更好地理解系统运行状况、快速定位问题以及优化性能。可观测2.0融合 MCP,可以让用户更好地感知系统、分析问题——用自然语言开启与系统的对话!本文将分享6个设计 MCP Server 的亲身实践,帮助大家更好地融合与使用。
316 75
MCP for 可观测2.0,6个让MCP开发更高效的小妙招
|
7天前
|
存储 监控 供应链
RFID库房进出入管理
RFID库房进出管理通过在货物或货箱上安装RFID标签,实现自动化信息采集,无需人工记录或扫描条码,大幅提升效率。系统结合入口、出口及内部关键位置的RFID阅读器,实时监控货物流动与位置变化。后台管理系统支持货物信息管理、库存盘点、出入库记录等功能,减少人工错误,优化库房作业流程。手持设备和固定阅读器配合使用,快速完成盘点并生成差异报告。RFID技术助力可视化管理,降低时间成本,提高准确性,为库存优化提供可靠支持。
|
12天前
|
监控 Kubernetes Go
日志采集效能跃迁:iLogtail 到 LoongCollector 的全面升级
LoongCollector 在日志场景中实现了全面的重磅升级,从功能、性能、稳定性等各个方面均进行了深度优化和提升,本文我们将对 LoongCollector 的升级进行详细介绍。
225 83
|
8天前
|
人工智能 安全 API
Higress MCP Server 安全再升级:API 认证为 AI 连接保驾护航
Higress MCP Server 新增了 API 认证功能,为 AI 连接提供安全保障。主要更新包括:1) 客户端到 MCP Server 的认证,支持 Key Auth、JWT Auth 和 OAuth2;2) MCP Server 到后端 API 的认证,增强第二阶段的安全性。新增功能如可重用认证方案、工具特定后端认证、透明凭证透传及灵活凭证管理,确保安全集成更多后端服务。通过 openapi-to-mcp 工具简化配置,减少手动工作量。企业版提供更高可用性保障,详情参见文档链接。
162 28
|
1月前
|
人工智能 JSON 安全
MCP Server 实践之旅第 1 站:MCP 协议解析与云上适配
本文深入解析了Model Context Protocol(MCP)协议,探讨其在AI领域的应用与技术挑战。MCP作为AI协作的“USB-C接口”,通过标准化数据交互解决大模型潜力释放的关键瓶颈。文章详细分析了MCP的生命周期、传输方式(STDIO与SSE),并提出针对SSE协议不足的优化方案——MCP Proxy,实现从STDIO到SSE的无缝转换。同时,函数计算平台被推荐为MCP Server的理想运行时,因其具备自动弹性扩缩容、高安全性和按需计费等优势。最后,展望了MCP技术演进方向及对AI基础设施普及的推动作用,强调函数计算助力MCP大规模落地,加速行业创新。
850 77
|
15天前
|
人工智能 安全 应用服务中间件
阿里巴巴 MCP 分布式落地实践:快速转换 HSF 到 MCP server
本文分享了阿里巴巴内部将大规模HSF服务快速转换为MCP Server的实践经验,通过Higress网关实现MCP协议卸载,无需修改代码即可接入MCP生态。文章分析了MCP生态面临的挑战,如协议快速迭代和SDK不稳定性,并详细介绍了操作步骤及组件功能。强调MCP虽非终极解决方案,但作为AI业务工程化的起点具有重要意义。最后总结指出,MCP只是AI原生应用发展的第一步,未来还有更多可能性值得探索。
550 45
OSZAR »