SpringBoot中操作Bean的生命周期的方法

引言

在 Spring Boot 应用中,管理和操作 Bean 的生命周期是一项关键的任务。这不仅涉及到如何创建和销毁 Bean,还包括如何在应用的生命周期中对 Bean 进行精细控制。Spring 框架提供了多种机制来管理 Bean 的生命周期,这些机制使得开发者可以根据具体的业务需求和场景来定制 Bean 的行为。从简单的注解到实现特定的接口,每种方法都有其适用的场景和优势。

在 Spring Boot 中,操作 Bean 生命周期的方法主要包括以下:

1. InitializingBean 和 DisposableBean 接口:

在某些环境或特定的约束下,如果您想避免使用 JSR-250

  • InitializingBean 接口提供了一个方法 afterPropertiesSet(),该方法在 Bean 属性设置之后调用。

  • DisposableBean 接口提供了一个方法 destroy(),该方法在 Bean 销毁之前调用。

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;public class MyBean implements InitializingBean, DisposableBean {@Overridepublic void afterPropertiesSet() throws Exception {// 初始化代码System.out.println("Bean is initialized");}@Overridepublic void destroy() throws Exception {// 清理代码System.out.println("Bean is destroyed");}
}

2. @PostConstruct 和 @PreDestroy 注解:

这两个是案例1中相对应的注解方式

  • @PostConstruct 注解用于在依赖注入完成后执行初始化方法。

  • @PreDestroy 注解用于在 Bean 销毁之前执行清理方法。

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;public class MyBean {@PostConstructpublic void init() {// 初始化代码System.out.println("Bean is initialized");}@PreDestroypublic void cleanup() {// 清理代码System.out.println("Bean is destroyed");}
}

3. Bean 定义的 initMethod 和 destroyMethod

第三种方式的初始化和销毁方法

  • 在 Bean 定义中,可以通过 initMethod 和 destroyMethod 属性指定初始化和销毁方法。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Bean(initMethod = "init", destroyMethod = "cleanup")public MyBean myBean() {return new MyBean();}public static class MyBean {public void init() {// 初始化代码System.out.println("Bean is initialized");}public void cleanup() {// 清理代码System.out.println("Bean is destroyed");}}
}

4. 实现 BeanPostProcessor 接口:

  • BeanPostProcessor 接口提供了两个方法:postProcessBeforeInitialization 和 postProcessAfterInitialization,分别在 Bean 初始化之前和之后调用。

  • 这可以用于在 Bean 初始化的不同阶段执行自定义逻辑。

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {// 在初始化之前执行的代码return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {// 在初始化之后执行的代码return bean;}
}

5. 实现 SmartLifecycle 接口:

图片

  • SmartLifecycle 是一个扩展的接口,用于更复杂的生命周期管理,特别是在有多个 Bean 依赖关系的场景中。

  • 它提供了启动和停止控制,以及对应的回调方法。

import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicBoolean;@Component
public class MySmartLifecycleBean implements SmartLifecycle {private static final Logger logger = LoggerFactory.getLogger(MySmartLifecycleBean.class);private final AtomicBoolean isRunning = new AtomicBoolean(false);@Overridepublic void start() {// 启动逻辑if (isRunning.compareAndSet(false, true)) {// 实际的启动逻辑initializeResources();logger.info("Lifecycle bean started");}}@Overridepublic void stop() {// 停止逻辑if (isRunning.compareAndSet(true, false)) {// 实际的停止逻辑releaseResources();logger.info("Lifecycle bean stopped");}}@Overridepublic boolean isRunning() {return isRunning.get();}@Overridepublic int getPhase() {// 控制启动和停止的顺序return 0; // 默认阶段是 0,可以根据需要调整}private void initializeResources() {// 具体的资源初始化逻辑}private void releaseResources() {// 具体的资源释放逻辑}
}

6. 使用 ApplicationListener 或 @EventListener

  • 这些用于监听应用事件,如上下文刷新、上下文关闭等,可以在这些事件发生时执行特定逻辑。

  • ApplicationListener 是一个接口,而 @EventListener 是一个注解,两者都可以用于监听应用事件。

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;@Component
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {// 在应用上下文刷新时执行的代码System.out.println("Application Context Refreshed");}
}// 或者使用 @EventListener
@Component
public class MyEventListener {@EventListenerpublic void handleContextRefresh(ContextRefreshedEvent event) {System.out.println("Handling context refreshed event.");}
}

7. 实现 ApplicationContextAware 和 BeanNameAware 接口:

  • 这些接口允许 Bean 在其生命周期内访问 ApplicationContext 和自身的 Bean 名称。

  • 通过实现这些接口,Bean 可以获得对 Spring 容器更深层次的访问和控制。

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;@Component
public class MyAwareBean implements ApplicationContextAware, BeanNameAware {private static final Logger logger = LoggerFactory.getLogger(MyAwareBean.class);private ApplicationContext applicationContext;private String beanName;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {this.applicationContext = applicationContext;// 可以在这里执行与应用上下文相关的操作logger.info("ApplicationContext has been set for Bean: {}", beanName);}@Overridepublic void setBeanName(String name) {this.beanName = name;// 记录 Bean 名称logger.info("Bean name set to {}", name);}// 示例方法,展示如何使用 applicationContextpublic void performSomeAction() {try {// 示例逻辑,例如检索其他 Bean 或环境属性// String someProperty = applicationContext.getEnvironment().getProperty("some.property");// ... 执行操作} catch (Exception e) {logger.error("Error during performing some action", e);}}
}

8. 使用 FactoryBean

  • FactoryBean 是一种特殊的 Bean,用于生成其他 Bean。

  • 可以通过实现 FactoryBean 接口来控制 Bean 的实例化过程。

import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;@Component
public class MyFactoryBean implements FactoryBean<MyCustomBean> {@Overridepublic MyCustomBean getObject() throws Exception {return new MyCustomBean();}@Overridepublic Class<?> getObjectType() {return MyCustomBean.class;}
}public class MyCustomBean {// 自定义 Bean 的逻辑
}

9. 使用 EnvironmentAware 和 ResourceLoaderAware 接口:

  • 这些接口允许 Bean 在其生命周期内访问 Spring 的 Environment 和资源加载器(ResourceLoader)。

  • 通过实现这些接口,Bean 可以获得对环境属性和资源的访问。

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;@Component
public class MyEnvironmentAwareBean implements EnvironmentAware, ResourceLoaderAware {private Environment environment;private ResourceLoader resourceLoader;@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic void setResourceLoader(ResourceLoader resourceLoader) {this.resourceLoader = resourceLoader;}
}

10. 实现 BeanFactoryAware 接口:

  • 通过实现 BeanFactoryAware 接口,Bean 可以访问到 Spring 容器中的 BeanFactory,从而可以进行更复杂的依赖注入和管理,BeanFactoryAware 应该在需要动态访问或管理 Bean 时作为特殊用例来使用。

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;@Component
public class MyBeanFactoryAware implements BeanFactoryAware {private BeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;}
}

11. 使用 @Profile 注解:

  • @Profile 注解允许根据不同的环境配置(如开发、测试、生产)来激活或禁用特定的 Bean。

  • 这对于控制 Bean 在不同环境下的创建和管理非常有用。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;@Configuration
public class MyConfiguration {@Bean@Profile("development")public MyBean devMyBean() {return new MyBean();}@Bean@Profile("production")public MyBean prodMyBean() {return new MyBean();}public static class MyBean {// Bean 实现}
}

12. 使用 @Lazy 注解:

  • @Lazy 注解用于延迟 Bean 的初始化直到它被首次使用。

  • 这对于优化启动时间和减少内存占用非常有用,特别是对于那些不是立即需要的 Bean。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;@Configuration
public class MyConfiguration {@Bean@Lazypublic MyBean myLazyBean() {return new MyBean();}public static class MyBean {// Bean 实现}
}

13. 使用 @DependsOn 注解:

  • @DependsOn 注解用于声明 Bean 的依赖关系,确保一个 Bean 在另一个 Bean 之后被初始化。

  • 这在管理 Bean 之间的依赖和初始化顺序时非常有用。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;@Configuration
public class MyConfiguration {@Bean@DependsOn("anotherBean")public MyBean myBean() {return new MyBean();}@Beanpublic AnotherBean anotherBean() {return new AnotherBean();}public static class MyBean {// Bean 实现}public static class AnotherBean {// 另一个 Bean 实现}
}

14. 使用 @Order 或 Ordered 接口:

  • 这些用于定义 Bean 初始化和销毁的顺序。

  • @Order 注解和 Ordered 接口可以帮助确保 Bean 按照特定的顺序被创建和销毁。

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class MyHighPriorityBean {// 高优先级 Bean 实现
}@Component
public class MyDefaultPriorityBean {// 默认优先级 Bean 实现
}

15. 使用 @Conditional 注解:

  • @Conditional 注解用于基于特定条件创建 Bean。

  • 你可以创建自定义条件或使用 Spring 提供的条件,如操作系统类型、环境变量、配置属性等。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;@Configuration
public class MyConfiguration {@Bean@Conditional(MyCondition.class)public MyBean myConditionalBean() {return new MyBean();}public static class MyBean {// Bean 实现}public static class MyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Environment env = context.getEnvironment();// 定义条件逻辑return env.containsProperty("my.custom.condition");}}
}

总结

Spring Boot 提供的这些方法使得开发者能够灵活地控制 Bean 的生命周期,从而满足不同的应用需求和场景。无论是简单的应用还是复杂的企业级系统,合理地利用这些机制可以有效地管理 Bean 的生命周期,提高应用的性能和可维护性。选择哪种方法取决于具体的需求、应用的复杂性以及开发团队的偏好。正确地使用这些工具和技术可以使 Spring Boot 应用更加健壮、灵活和高效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/788866.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows部署Jenkins并远程部署tomcat

目录 1、Jenkins官网下载Jenkins 2、安装Jenkins 3、修改Home directory 4、插件安装及系统配置 5、Tomcat安装及配置 5.1、修改配置文件,屏蔽以下代码 5.2、新增登录用户 5.3、编码格式修改 5.4、启动tomcat 6、Jenkins远程部署war包 6.1、General配置 6.2、Sourc…

AKF扩展立方体和AKF可用性立方体

很多人知道AKF扩展立方体是从《架构即未来》这本书开始。实际上akfpartners官方写过4篇关于AKF扩展立方体的文章&#xff0c;还有一篇介绍AKF可用性立方体。akfpartners官方在高可用、扩展性方面有很多专业技术文章&#xff0c;建议有空就翻翻看。 AKF扩展立方体和AKF可用性立方…

C++之结构体初始化10种写法总结(二百六十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

是否有替代U盘,可安全交换的医院文件摆渡方案?

医院内部网络存储着大量的敏感医疗数据&#xff0c;包括患者的个人信息、病历记录、诊断结果等。网络隔离可以有效防止未经授权的访问和数据泄露&#xff0c;确保这些敏感信息的安全。随着法律法规的不断完善&#xff0c;如《网络安全法》、《个人信息保护法》等&#xff0c;医…

[lesson02]C到C++的升级

C到C的升级 C与C的关系 C继承了所有的C特性C在C的基础上提供了更多的语法和特性C的设计目标是运行效率与开发效率的统一 C到C的升级 C更强调语言的实用性 所有的变量都可以在需要使用时再定义 int c 0; for (int i 1; i < 3; i) {for(int j 1; j < 3; j){c i * …

EVM Layer2 主流解决方案

深度解析主流 EVM Layer 2 解决方案&#xff1a;zk Rollups 和 Optimistic Rollups 随着以太坊网络的不断演进和 DeFi 生态系统的迅速增长&#xff0c;以太坊 Layer 2 解决方案日益受到关注。 其中&#xff0c;zk Rollups 和 Optimistic Rollups 作为两种备受瞩目的主流 EVM&…

【AAOS车载系统+AOSP14系统攻城狮入门实战课】:正式上线了(二百零三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

数据如何才能供得出、流得动、用得好、还安全

众所周知&#xff0c;数据要素已经列入基本生产要素&#xff0c;同时成立国家数据局进行工作统筹。目前数据要素如何发挥其价值&#xff0c;全国掀起了一浪一浪的热潮。 随着国外大语言模型的袭来&#xff0c;国内在大语言模型领域的应用也大放异彩&#xff0c;与此同时&#x…

使用docker部署MongoDB数据库

最近由于工作需要搭建MongoDB数据库&#xff1a;将解析的车端采集的数据写入到数据库&#xff0c;由于MongoDB高可用、海量扩展、灵活数据的模型&#xff0c;因此选用MongoDB数据库&#xff1b;由于现公司只有服务器&#xff0c;因此考虑容器化部署MongoDB数据&#xff0c;特此…

db2 使用jdbc建立连接时,指定schema,schema不存在也会连接成功

使用db2想指定schema&#xff0c;使用语句如下 jdbc:db2://" hostname ":" port "/" databaseName ":currentSchema" this.databaseSchema ";"; 切记&#xff1a;最后的分号一定要有&#xff0c;否则报错。 但是此处有…

Android手势密码–设置和校验功能的实现代码

效果图如下&#xff0c;大家感觉不错请参考实现代码 具体代码如下所示&#xff1a; private void setGesturePassword() {toggleMore.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {Overridepublic void onCheckedChanged(CompoundButton button…

【linux】lsof命令使用

1. 功能 lsof list open files, 列出被进程所使用的文件名称。 2. 基础语法 3. 参数含义 参数含义-a过滤出多个选项要同时满足的文件-U仅列出UNIX-like系统的socket文件类型。-u指定用户&#xff0c;比如-u atiaisi&#xff0c;会把用户atiaisi相关的进程使用的文件列出来。…

24/04/02总结

API: bigdecima: 方法名 说明 public static BigDecimal valueof( double val) 静态获取对象 public BigDecimal add(BigDecimal val) 加法 public BigDecimal subtract(BigDecimal val…

【路径规划论文整理(1)】Path Deformation Roadmaps(附带对PRM改进算法、同伦映射的整理)

本系列主要是对精读的一些关于路径搜索论文的整理&#xff0c;包括了论文所拓展的其他一些算法的改进思路。 这是本系列的第一篇文章&#xff1a; Jaillet, Lonard & Simon, Thierry. (2008). Path Deformation Roadmaps: Compact Graphs with Useful Cycles for Motion Pl…

Spring Boot接收从前端传过来的数据常用方式以及处理的技巧

一、params 传参 参数是会拼接到url后面的请求 场景规范:url后面的key值<=3个参数的时候,使用params 传参 支持的请求方式:get(正规的是get方式)、post 都行 例如: http://localhost:8080/simpleParam?name=Tom&age=10 在postman里面的体现为 后端接收的接口…

格式化输出数据

JDK 5 新特性&#xff0c;格式化输出数据 长度不够前面补空格&#xff0c;超出长度按实际输出 System.out.printf(“格式控制部分”,表达式1,表达式2,,表达式n); 格式控制部分由格式符号、普通字符组成&#xff0c;普通字符原样输出&#xff0c;格式符号输出表达式的值 // …

Python+requests+Pytest+logging+allure+pymysql框架详解

一、框架目录结构 1)tools目录用来放公共方法存储,如发送接口以及读取测试数据的方法,响应断言 数据库断言 前置sql等方法;2)datas目录用例存储接口用例的测试数据,我是用excel来存储的数据,文件数据 图片数据等;3)testcases目录用来存放测试用例,一个python文件对应…

Python网络爬虫(一):HTML/CSS/JavaScript介绍

1 HTML语言 1.1 HTML简介 HTML指的是超文本标记语言&#xff1a;HyperText Markup Language&#xff0c;它不是一门编程语言&#xff0c;而是一种标记语言&#xff0c;即一套标记标签。HTML是纯文本类型的语言&#xff0c;使用HTML编写的网页文件也是标准的文本文件&#xff0c…

天盾网络验证源码+视频教程

最新版本为746&#xff0c;企业定制版。现在正在意义上的离线版已出来&#xff0c; 天盾746离线版不需要绑定电脑&#xff0c;提供母端&#xff0c;断网可用&#xff0c;可以理解为它是一款离线版的工具。它没有任何使用限制&#xff0c;和正版唯一的区别就是不需要连接作者服…

789. 数的范围 (二分学习)

题目链接 1.确定一个区间&#xff0c;使得目标值一定在区间中 2.找一个性质满足&#xff1a; &#xff08;1&#xff09;性质具有二段性 &#xff08;2&#xff09;答案是二段性的分界点 3.整数二分&#xff08;处理红色右端点和绿色左端点&#xff09; //代码1&#xff1a;…