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

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置