SpringBoot:Bean生命周期自定义初始化和销毁

简介: SpringBoot:Bean生命周期自定义初始化和销毁



前言

上篇文章详细讲诉了Bean的生命周期和作用域,在生命周期中提到了如何自定义初始化Bean,可能很多人不知道如何自定义初始化,这里详细补充讲解一下:使用@Bean注解指定初始化和销毁方法、实现InitializingBean接口和DisposableBean接口自定义初始化和销毁、@PostConstruct(初始化逻辑)和@PreDestroy(销毁逻辑)注解、使用BeanPostProcessor接口。


一、@Bean注解指定初始化和销毁方法

  • 创建BeanTest类,自定义初始化方法和销毁方法。
  • 在@Bean注解的参数中指定BeanTest自定义的初始化和销毁方法:
  • 销毁方法只有在IOC容器关闭的时候才调用。

代码如下:

/**
 * @Version: 1.0.0
 * @Author: Dragon_王
 * @ClassName: dog
 * @Description: TODO描述
 * @Date: 2024/1/21 22:55
 */
public class BeanTest {
    public BeanTest(){
        System.out.println("BeanTest被创建");
    }
    public void init(){
        System.out.println("BeanTest被初始化");
    }
    public void destory(){
        System.out.println("BeanTest被销毁");
    }
}
/**
 * @Version: 1.0.0
 * @Author: Dragon_王
 * @ClassName: MyConfig
 * @Description: TODO描述
 * @Date: 2024/1/21 22:59
 */
@Configuration
@ComponentScan(("com.dragon.restart1"))
public class MyConfig {
    @Bean(initMethod = "init",destroyMethod = "destory")
    public BeanTest beanTest(){
        return new BeanTest();
    }
}
//测试代码
AnnotationConfigApplicationContext ct = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println("IoC容器创建完成");

  • 可以看到调用的是自定义的方法,这里解释一下,测试时,运行完代码块程序就结束了,所哟IoC容器就被关闭,所以调用了IoC销毁方法。同时可以看到初始化方法在对象创建完成后调用。
  • 当组件的作用域为单例时在容器启动时即创建对象,而当作用域为原型(PROTOTYPE)时在每次获取对象的时候才创建对象。并且当作用域为原型(PROTOTYPE)时,IOC容器只负责创建Bean但不会管理Bean,所以IOC容器不会调用销毁方法。

二、实现InitializingBean接口和DisposableBean接口

看一下两接口的方法:

public interface InitializingBean {
  /**
   * Invoked by the containing {@code BeanFactory} after it has set all bean properties
   * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
   * <p>This method allows the bean instance to perform validation of its overall
   * configuration and final initialization when all bean properties have been set.
   * @throws Exception in the event of misconfiguration (such as failure to set an
   * essential property) or if initialization fails for any other reason
   * Bean都装配完成后执行初始化
   */
  void afterPropertiesSet() throws Exception;
}
====================================================================
public interface DisposableBean {
  /**
   * Invoked by the containing {@code BeanFactory} on destruction of a bean.
   * @throws Exception in case of shutdown errors. Exceptions will get logged
   * but not rethrown to allow other beans to release their resources as well.
   */
  void destroy() throws Exception;
}

代码如下:

/**
 * @Version: 1.0.0
 * @Author: Dragon_王
 * @ClassName: BeanTest1
 * @Description: TODO描述
 * @Date: 2024/1/21 23:25
 */
public class BeanTest1 implements InitializingBean, DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("BeanTest1销毁");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("BeanTest1初始化");
    }
    public BeanTest1() {
        System.out.println("BeanTest1被创建");
    }
}
=========================
@Configuration
@ComponentScan(("com.dragon.restart1"))
public class MyConfig {
 @Bean
    public BeanTest1 beanTest1(){
        return new BeanTest1();
    }
}

三、@PostConstruct(初始化逻辑)和@PreDestroy(销毁逻辑)注解

  • 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法。
  • 被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
  • 被@PreDestroy修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreDestroy修饰的方法会在destroy()方法之后运行,在Servlet被彻底卸载之前。

代码如下:

/**
 * @Version: 1.0.0
 * @Author: Dragon_王
 * @ClassName: BeanTest2
 * @Description: TODO描述
 * @Date: 2024/1/21 23:32
 */
public class BeanTest2 {
    public BeanTest2(){
        System.out.println("BeanTest2被创建");
    }
    @PostConstruct
    public void init(){
        System.out.println("BeanTest2被初始化");
    }
    @PreDestroy
    public void destory(){
        System.out.println("BeanTest2被销毁");
    }
}
========================
//
@Configuration
@ComponentScan(("com.dragon.restart1"))
public class MyConfig {
 @Bean
    public BeanTest2 beanTest2(){
        return new BeanTest2();
    }
}

四、BeanPostProcessor接口

BeanPostProcessor又叫Bean的后置处理器,是Spring框架中IOC容器提供的一个扩展接口,在Bean初始化的前后进行一些处理工作。

BeanPostProcessor的源码如下:

public interface BeanPostProcessor {
  /**
   * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
   * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
   * or a custom init-method). The bean will already be populated with property values.
   * The returned bean instance may be a wrapper around the original.
   * <p>The default implementation returns the given {@code bean} as-is.
   * @param bean the new bean instance
   * @param beanName the name of the bean
   * @return the bean instance to use, either the original or a wrapped one;
   * if {@code null}, no subsequent BeanPostProcessors will be invoked
   * @throws org.springframework.beans.BeansException in case of errors
   * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
   */
  @Nullable
    //bean初始化方法调用前被调用
  default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
  /**
   * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
   * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
   * or a custom init-method). The bean will already be populated with property values.
   * The returned bean instance may be a wrapper around the original.
   * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
   * instance and the objects created by the FactoryBean (as of Spring 2.0). The
   * post-processor can decide whether to apply to either the FactoryBean or created
   * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
   * <p>This callback will also be invoked after a short-circuiting triggered by a
   * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
   * in contrast to all other BeanPostProcessor callbacks.
   * <p>The default implementation returns the given {@code bean} as-is.
   * @param bean the new bean instance
   * @param beanName the name of the bean
   * @return the bean instance to use, either the original or a wrapped one;
   * if {@code null}, no subsequent BeanPostProcessors will be invoked
   * @throws org.springframework.beans.BeansException in case of errors
   * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
   * @see org.springframework.beans.factory.FactoryBean
   */
  @Nullable
  //bean初始化方法调用后被调用
  default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }

代码如下:

/**
 * @Version: 1.0.0
 * @Author: Dragon_王
 * @ClassName: MyBeanPostProcess
 * @Description: TODO描述
 * @Date: 2024/1/21 23:40
 */
@Component
public class MyBeanPostProcess implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
        return bean;
    }
}
============================
@Configuration
@ComponentScan(("com.dragon.restart1"))
public class MyConfig {
    @Bean
    public BeanTest1 beanTest1(){
        return new BeanTest1();
    }
    @Bean
    public BeanTest2 beanTest2(){
        return new BeanTest2();
    }
}

运行结果如下:

BeanTest1被创建
postProcessBeforeInitialization...beanTest1=>com.dragon.restart1.BeanTest1@111d5c97
BeanTest1初始化
postProcessAfterInitialization...beanTest1=>com.dragon.restart1.BeanTest1@111d5c97
BeanTest2被创建
postProcessBeforeInitialization...beanTest2=>com.dragon.restart1.BeanTest2@29c17c3d
BeanTest2被初始化
postProcessAfterInitialization...beanTest2=>com.dragon.restart1.BeanTest2@29c17c3d
IoC容器创建完成
BeanTest2被销毁
BeanTest1销毁

通过上述运行结果可以发现使用BeanPostProcessor的运行顺序为

IOC容器实例化Bean---->调用BeanPostProcessor的postProcessBeforeInitialization方法---->调用bean实例的初始化方法---->调用BeanPostProcessor的postProcessAfterInitialization方法。


总结

以上就是Bean生命周期自定义初始化和销毁的讲解。

相关文章
|
1月前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
152 0
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
163 2
|
11天前
|
Java
SpringBoot构建Bean(RedisConfig + RestTemplateConfig)
SpringBoot构建Bean(RedisConfig + RestTemplateConfig)
31 2
|
1月前
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
1月前
|
Java Spring 容器
Springboot3.2.1搞定了类Service和bean注解同名同类型问题修复
这篇文章讨论了在Spring Boot 3.2.1版本中,同名同类型的bean和@Service注解类之间冲突的问题得到了解决,之前版本中同名bean会相互覆盖,但不会在启动时报错,而在配置文件中设置`spring.main.allow-bean-definition-overriding=true`可以解决这个问题。
85 0
Springboot3.2.1搞定了类Service和bean注解同名同类型问题修复
|
1月前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
58 2
|
1月前
|
前端开发 Java 数据库
springBoot:template engine&自定义一个mvc&后端给前端传数据&增删改查 (三)
本文介绍了如何自定义一个 MVC 框架,包括后端向前端传递数据、前后端代理配置、实现增删改查功能以及分页查询。详细展示了代码示例,从配置文件到控制器、服务层和数据访问层的实现,帮助开发者快速理解和应用。
|
1月前
|
Java Shell C++
Springboot加载注入bean的方式
本文详细介绍了Spring Boot中Bean的装配方法。首先讲解了使用@Component、@Service、@Controller、@Repository等注解声明Bean的方式,并解释了这些注解之间的关系及各自适用的层次。接着介绍了通过@Configuration和@Bean注解定义Bean的方法,展示了其灵活性和定制能力。最后讨论了@Component与@Bean的区别,并提供了在Spring Boot应用中装配依赖包中Bean的三种方法:使用@ComponentScan注解扫描指定包、使用@Import注解导入特定Bean以及在spring.factories文件中配置Bean。
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
144 1
|
18天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
95 62