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

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听