Spring 源码解读:实现Bean的初始化与销毁机制

2024-08-30 06:44

本文主要是介绍Spring 源码解读:实现Bean的初始化与销毁机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

在Spring框架中,Bean的生命周期管理是非常重要的一个方面。Spring提供了多种方式来管理Bean的初始化和销毁,例如通过@PostConstruct@PreDestroy注解定义初始化和销毁方法。本篇文章将通过自定义实现来讲解如何手动管理Bean的初始化与销毁,同时对比Spring中的相关注解,深入理解Bean生命周期管理的实现方式及其重要性。

Bean生命周期管理的基本概念

在Spring中,Bean的生命周期涵盖了从Bean的创建、初始化、使用到销毁的全过程。Spring通过一系列回调接口、注解和配置,提供了灵活的Bean生命周期管理机制。在实际开发中,合理管理Bean的生命周期可以帮助我们在适当的时机进行资源初始化和释放,提升应用的健壮性和可维护性。

Bean的生命周期

  1. 实例化:Spring容器根据BeanDefinition创建Bean实例。
  2. 属性赋值:Spring容器将Bean的属性值注入到Bean实例中。
  3. 初始化:在属性赋值完成后,Spring容器调用Bean的初始化方法。
  4. 使用:Bean处于就绪状态,可以被Spring容器使用。
  5. 销毁:在容器关闭时,Spring容器调用Bean的销毁方法,释放资源。

手动实现Bean的初始化与销毁方法

自定义注解@Init@Destroy

我们首先定义两个自定义注解,@Init用于标识Bean的初始化方法,@Destroy用于标识Bean的销毁方法。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Init注解,用于标识Bean的初始化方法*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Init {
}/*** @Destroy注解,用于标识Bean的销毁方法*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Destroy {
}

扩展SimpleBeanFactory实现初始化与销毁

在前面实现的SimpleBeanFactory基础上,我们扩展其功能,使其支持对@Init@Destroy方法的调用。

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;/*** 自定义的简单Bean工厂,支持@Bean注解、@Init注解和@Destroy注解*/
public class SimpleBeanFactory {// 存储已创建的Bean实例private Map<String, Object> beanMap = new HashMap<>();// 存储Bean的定义信息,包括Bean的类、初始化方法和销毁方法private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();/*** 构造方法,扫描配置类并注册Bean定义* @param configClass 配置类*/public SimpleBeanFactory(Class<?> configClass) {// 扫描配置类中的所有方法for (Method method : configClass.getDeclaredMethods()) {// 检查方法是否标注了@Bean注解if (method.isAnnotationPresent(Bean.class)) {// 创建BeanDefinition并设置Bean的类信息BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setBeanClass(method.getReturnType());// 扫描Bean类的方法,查找@Init和@Destroy注解for (Method beanMethod : method.getReturnType().getDeclaredMethods()) {if (beanMethod.isAnnotationPresent(Init.class)) {beanDefinition.setInitMethod(beanMethod);}if (beanMethod.isAnnotationPresent(Destroy.class)) {beanDefinition.setDestroyMethod(beanMethod);}}// 将BeanDefinition注册到beanDefinitionMap中beanDefinitionMap.put(method.getName(), beanDefinition);}}}/*** 获取Bean实例* @param name Bean的名称* @return Bean实例*/public Object getBean(String name) {// 如果Bean实例已经存在于beanMap中,直接返回if (beanMap.containsKey(name)) {return beanMap.get(name);}// 从beanDefinitionMap中获取BeanDefinitionBeanDefinition beanDefinition = beanDefinitionMap.get(name);if (beanDefinition == null) {throw new RuntimeException("No bean named " + name + " is defined");}try {// 创建Bean实例Object bean = beanDefinition.getBeanClass().getDeclaredConstructor().newInstance();// 如果Bean定义了初始化方法,调用该方法if (beanDefinition.getInitMethod() != null) {beanDefinition.getInitMethod().invoke(bean);}// 将创建的Bean实例存储到beanMap中beanMap.put(name, bean);return bean;} catch (Exception e) {throw new RuntimeException("Failed to create bean " + name, e);}}/*** 销毁Bean实例* @param name Bean的名称*/public void destroyBean(String name) {// 获取Bean实例Object bean = beanMap.get(name);if (bean != null) {// 获取Bean的定义信息BeanDefinition beanDefinition = beanDefinitionMap.get(name);try {// 如果Bean定义了销毁方法,调用该方法if (beanDefinition.getDestroyMethod() != null) {beanDefinition.getDestroyMethod().invoke(bean);}// 从beanMap中移除Bean实例beanMap.remove(name);} catch (Exception e) {throw new RuntimeException("Failed to destroy bean " + name, e);}}}/*** 获取BeanDefinition* @param name Bean的名称* @return BeanDefinition实例*/public BeanDefinition getBeanDefinition(String name) {return beanDefinitionMap.get(name);}
}

BeanDefinition类的扩展

我们需要在BeanDefinition类中增加对初始化方法和销毁方法的支持。

import java.lang.reflect.Method;/*** BeanDefinition类,用于存储Bean的元数据信息*/
public class BeanDefinition {// Bean的类private Class<?> beanClass;// 初始化方法private Method initMethod;// 销毁方法private Method destroyMethod;public Class<?> getBeanClass() {return beanClass;}public void setBeanClass(Class<?> beanClass) {this.beanClass = beanClass;}public Method getInitMethod() {return initMethod;}public void setInitMethod(Method initMethod) {this.initMethod = initMethod;}public Method getDestroyMethod() {return destroyMethod;}public void setDestroyMethod(Method destroyMethod) {this.destroyMethod = destroyMethod;}
}

测试初始化与销毁

我们通过一个简单的测试类来验证自定义的@Init@Destroy注解,以及扩展后的SimpleBeanFactory

/*** Service类,包含初始化和销毁方法*/
public class Service {@Initpublic void init() {System.out.println("Service is initialized.");}@Destroypublic void destroy() {System.out.println("Service is destroyed.");}public void execute() {System.out.println("Service is executing...");}
}/*** 配置类,定义一个Service Bean*/
public class AppConfig {@Beanpublic Service service() {return new Service();}
}/*** 测试类,验证Bean的初始化与销毁*/
public class Test {public static void main(String[] args) {SimpleBeanFactory factory = new SimpleBeanFactory(AppConfig.class);// 获取并使用BeanService service = (Service) factory.getBean("service");service.execute();// 销毁Beanfactory.destroyBean("service");}
}

详细解读

  • Service类中定义了initdestroy方法,分别用@Init@Destroy注解标识。
  • AppConfig类中定义了一个名为service的Bean。
  • Test类中,我们通过SimpleBeanFactory获取service Bean并调用其方法,然后在销毁Bean时调用销毁方法。

类图和流程图

为了更好地理解整个流程,我们提供了类图和流程图。

类图
uses
SimpleBeanFactory
-Map<String, Object> beanMap
-Map<String, BeanDefinition> beanDefinitionMap
+SimpleBeanFactory(Class<?> configClass)
+Object getBean(String name)
+void destroyBean(String name)
+BeanDefinition getBeanDefinition(String name)
BeanDefinition
-Class<?> beanClass
-Method initMethod
-Method destroyMethod
+Class~?~ getBeanClass()
+void setBeanClass(Class<?> beanClass)
+Method getInitMethod()
+void setInitMethod(Method initMethod)
+Method getDestroyMethod()
+void setDestroyMethod(Method destroyMethod)
AppConfig
+Service service()
Service
+void init()
+void destroy()
+void execute()

解释

  • SimpleBeanFactory类负责管理Bean的生命周期,包括初始化和销毁。
  • BeanDefinition类存储了Bean的元数据信息,包括初始化和销毁方法。
  • AppConfig类定义了一个标注了@Bean注解的service()方法。
流程图
SimpleBeanFactory构造器
扫描AppConfig类的方法
检查方法是否标注了 Bean注解
创建BeanDefinition并存储元数据信息,包括初始化和销毁方法
调用方法并注册Bean
Bean和BeanDefinition存储在beanMap和beanDefinitionMap中
通过getBean获取Bean实例,调用初始化方法
通过destroyBean销毁Bean,调用销毁方法

解释

  • 流程图展示了SimpleBeanFactory如何通过反射扫描AppConfig类的方法,检查是否标注了@Bean注解,并注册Bean和BeanDefinition的过程。同时展示了如何在获取Bean实例时调用初始化方法,以及在销毁Bean时调用销毁方法。

Spring源码解读:@PostConstruct@PreDestroy注解的实现

在Spring中,@PostConstruct@PreDestroy注解是用来标识Bean的初始化和销毁方法的。@PostConstruct标识的方法会在Bean的依赖注入完成后自动调用,而@PreDestroy标识的方法会在Bean被销毁前调用。

@PostConstruct@PreDestroy 在Spring中的实现

Spring通过CommonAnnotationBeanPostProcessor类处理@PostConstruct@PreDestroy注解。这个类实现了BeanPostProcessor接口,可以在Bean初始化和销毁时执行特定的逻辑。

CommonAnnotationBeanPostProcessor
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor {private static final String POST_CONSTRUCT_METHOD_NAME = "postConstruct";private static final String PRE_DESTROY_METHOD_NAME = "preDestroy";public CommonAnnotationBeanPostProcessor() {super(POST_CONSTRUCT_METHOD_NAME, PRE_DESTROY_METHOD_NAME);}
}

详细解读

  • CommonAnnotationBeanPostProcessor:该类继承自InitDestroyAnnotationBeanPostProcessor,并指定了@PostConstruct@PreDestroy注解对应的方法名称。
  • InitDestroyAnnotationBeanPostProcessor:负责在Bean初始化后调用@PostConstruct标注的方法,在Bean销毁前调用@PreDestroy标注的方法。
InitDestroyAnnotationBeanPostProcessor 类的实现
public class InitDestroyAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {private final String initAnnotationType;private final String destroyAnnotationType;public InitDestroyAnnotationBeanPostProcessor(String initAnnotationType, String destroyAnnotationType) {this.initAnnotationType = initAnnotationType;this.destroyAnnotationType = destroyAnnotationType;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 扫描并调用@PostConstruct标注的方法invokeAnnotatedMethods(bean, this.initAnnotationType);return bean;}@Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {// 扫描并调用@PreDestroy标注的方法invokeAnnotatedMethods(bean, this.destroyAnnotationType);}private void invokeAnnotatedMethods(Object bean, String annotationType) {// 扫描bean的方法,查找并调用指定注解标注的方法Method[] methods = bean.getClass().getMethods();for (Method method : methods) {if (method.isAnnotationPresent(annotationType)) {try {method.invoke(bean);} catch (Exception ex) {throw new BeansException("Invocation of " + annotationType + " method failed", ex);}}}}
}

详细解读

  • postProcessBeforeInitialization 方法:在Bean初始化之前调用@PostConstruct标注的方法。
  • postProcessBeforeDestruction 方法:在Bean销毁之前调用@PreDestroy标注的方法。
  • invokeAnnotatedMethods 方法:通过反射机制扫描Bean的所有方法,查找并调用指定注解标注的方法。

对比与自定义实现

  • Spring的实现

    • @PostConstruct@PreDestroy注解是Java EE规范的一部分,Spring通过CommonAnnotationBeanPostProcessor类对其进行了支持,确保在Bean初始化和销毁时执行相应的方法。
    • Spring的实现非常简洁且易于使用,只需在方法上添加注解即可。
  • 自定义实现

    • 通过自定义的@Init@Destroy注解实现了类似的功能,虽然实现简单,但展示了Spring背后的设计思路。
    • 自定义实现更适合学习和理解Spring的核心机制。

总结

通过实现自定义的@Init@Destroy注解,以及扩展SimpleBeanFactory支持初始化和销毁方法的调用,并深入解读Spring源码中的@PostConstruct@PreDestroy注解处理机制,你应该对Spring中的Bean生命周期管理有了更深入的理解。这些知识不仅有助于你更好地使用Spring框架,也能帮助你在开发中有效管理Bean的生命周期。


互动与思考

在实际项目中,你是如何管理Bean的生命周期的?你认为在什么场景下需要自定义Bean的初始化和销毁方法?欢迎在评论区分享你的看法和经验!


如果你觉得这篇文章对你有帮助,请别忘了:

  • 点赞
  • 收藏 📁
  • 关注 👀

让我们一起深入学习Spring框架,成为更优秀的开发者!


这篇关于Spring 源码解读:实现Bean的初始化与销毁机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120078

相关文章

Qt实现对Word网页的读取功能

《Qt实现对Word网页的读取功能》文章介绍了几种在Qt中实现Word文档(.docx/.doc)读写功能的方法,包括基于QAxObject的COM接口调用、DOCX模板替换及跨平台解决方案,重点讨论... 目录1. 核心实现方式2. 基于QAxObject的COM接口调用(Windows专用)2.1 环境

MySQL查看表的历史SQL的几种实现方法

《MySQL查看表的历史SQL的几种实现方法》:本文主要介绍多种查看MySQL表历史SQL的方法,包括通用查询日志、慢查询日志、performance_schema、binlog、第三方工具等,并... 目录mysql 查看某张表的历史SQL1.查看MySQL通用查询日志(需提前开启)2.查看慢查询日志3.

Java实现字符串大小写转换的常用方法

《Java实现字符串大小写转换的常用方法》在Java中,字符串大小写转换是文本处理的核心操作之一,Java提供了多种灵活的方式来实现大小写转换,适用于不同场景和需求,本文将全面解析大小写转换的各种方法... 目录前言核心转换方法1.String类的基础方法2. 考虑区域设置的转换3. 字符级别的转换高级转换

使用Python实现局域网远程监控电脑屏幕的方法

《使用Python实现局域网远程监控电脑屏幕的方法》文章介绍了两种使用Python在局域网内实现远程监控电脑屏幕的方法,方法一使用mss和socket,方法二使用PyAutoGUI和Flask,每种方... 目录方法一:使用mss和socket实现屏幕共享服务端(被监控端)客户端(监控端)方法二:使用PyA

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

SpringBoot简单整合ElasticSearch实践

《SpringBoot简单整合ElasticSearch实践》Elasticsearch支持结构化和非结构化数据检索,通过索引创建和倒排索引文档,提高搜索效率,它基于Lucene封装,分为索引库、类型... 目录一:ElasticSearch支持对结构化和非结构化的数据进行检索二:ES的核心概念Index:

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav