使用spring容器在初始化Bean时前和后的操作
作者:Bwz_Learning 发布时间:2021-07-01 05:49:24
spring容器初始化Bean操作
在某些情况下,Spring容器在初始化Bean的时候,希望在初始化bean前和销毁bean前进行一些资源的加载和释放的操作。可以通过一下三种方式完成。
Bean的方法加上@PostConstruct和@PreDestroy注解
在xml中定义init-method和destory-method方法
Bean实现InitializingBean和DisposableBean接口
@PostConstruct和@PreDestroy注解
JavaBean代码
@Component
public class PersonService {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@PostConstruct
public void init() {
System.out.println("PersonService.class init method ...");
}
@PreDestroy
public void cleanUp() {
System.out.println("PersonService.class cleanUp method ...");
}
}
spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">
<!-- spring扫描的路径 -->
<context:component-scan base-package="spring.zhujie" />
</beans>
测试代码和结果
测试代码
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-zhujie.xml");
context.registerShutdownHook();
}
运行结果
PersonService.class init method ...
PersonService.class cleanUp method ...
在XML中定义init-method和destory-method方法
JavaBean代码
public class PersonService {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void init() {
System.out.println("PersonService.class init method ...");
}
public void cleanUp() {
System.out.println("PersonService.class cleanUp method ...");
}
}
spring配置文件
<bean class="spring.zhujie.PersonService" init-method="init" destroy-method="cleanUp"/>
测试代码和结果
测试代码
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-xml.xml");
context.registerShutdownHook();
}
运行结果
PersonService.class init method ...
六月 23, 2017 9:42:06 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@7a94c5e7: startup date [Fri Jun 23 21:42:06 CST 2017]; root of context hierarchy
PersonService.class cleanUp method ...
Bean实现InitializingBean和DisposableBean接口
JavaBean代码
public class PersonService implements InitializingBean, DisposableBean {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("PersonService.class init method ...");
}
@Override
public void destroy() throws Exception {
System.out.println("PersonService.class cleanUp method ...");
}
}
spring配置文件
<bean id="personService" class="spring.zhujie.PersonService" />
测试代码和结果
测试代码
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-interface.xml");
context.registerShutdownHook();
}
运行结果
PersonService.class init method ...
PersonService.class cleanUp method ...
Spring bean 初始化顺序
InitializingBean, init-method 和 PostConstruct
1、概述
从接口的名字上不难发现,InitializingBean 的作用就是在 bean 初始化后执行定制化的操作。
Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,常用的设定方式有以下三种:
通过实现 InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法;
通过 <bean> 元素的 init-method/destroy-method 属性指定初始化之后 /销毁之前调用的操作方法;
在指定方法上加上@PostConstruct 或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用。
2、InitializingBean vs init-method
接口定义如下:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
接口只有一个方法afterPropertiesSet,
此方法的调用入口是负责加载 spring bean 的AbstractAutowireCapableBeanFactory,源码如下:
protected void invokeInitMethods(String beanName, Object bean,
RootBeanDefinition mbd) throws Throwable {
boolean isInitializingBean = bean instanceof InitializingBean;
if ((isInitializingBean)
&& (((mbd == null) || (!(mbd
.isExternallyManagedInitMethod("afterPropertiesSet")))))) {
if (this.logger.isDebugEnabled()) {
this.logger
.debug("Invoking afterPropertiesSet() on bean with name '"
+ beanName + "'");
}
//先调用afterPropertiesSet()进行初始化
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction(bean) {
public Object run() throws Exception {
((InitializingBean) this.val$bean)
.afterPropertiesSet();
return null;
}
}, getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
((InitializingBean) bean).afterPropertiesSet();
}
}
//然后调用InitMethod()进行初始化
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if ((initMethodName == null)
|| ((isInitializingBean) && ("afterPropertiesSet"
.equals(initMethodName)))
|| (mbd.isExternallyManagedInitMethod(initMethodName)))
return;
invokeCustomInitMethod(beanName, bean, mbd);
}
}
从这段源码可以得出以下结论:
spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用
实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖
先调用afterPropertiesSet,再执行 init-method 方法,如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法
3、@PostConstruct
通过 debug 和调用栈找到类InitDestroyAnnotationBeanPostProcessor, 其中的核心方法,即 @PostConstruct 方法调用的入口:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
从命名上,我们就可以得到某些信息——这是一个BeanPostProcessor。BeanPostProcessor的postProcessBeforeInitialization是在Bean生命周期中afterPropertiesSet和init-method之前被调用的。另外通过跟踪,@PostConstruct方法的调用方式也是通过反射机制。
4、小结一下吧
spring bean的初始化执行顺序:构造方法 --> @PostConstruct注解的方法 --> afterPropertiesSet方法 --> init-method指定的方法。具体可以参考例子
afterPropertiesSet通过接口实现方式调用(效率上高一点),@PostConstruct和init-method都是通过反射机制调用
同理,bean销毁过程的顺序为:@PreDestroy > DisposableBean > destroy-method
不再展开,看源码就好
测试代码如下:
@Slf4j
public class InitSequenceBean implements InitializingBean {
public InitSequenceBean() {
log.info("InitSequenceBean: construct");
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("InitSequenceBean: afterPropertiesSet");
}
@PostConstruct
public void postConstruct() {
log.info("InitSequenceBean: postConstruct");
}
public void initMethod() {
log.info("InitSequenceBean: initMethod");
}
}
@Configuration
public class SystemConfig {
@Bean(initMethod = "initMethod", name = "initSequenceBean")
public InitSequenceBean initSequenceBean() {
return new InitSequenceBean();
}
}
@Slf4j
public class InitSequenceBeanTest extends ApplicationTests {
@Autowired
private InitSequenceBean initSequenceBean;
@Test
public void initSequenceBeanTest() {
log.info("Finish: {}", initSequenceBean.toString());
}
}
来源:https://blog.csdn.net/zbw18297786698/article/details/73656460


猜你喜欢
- 我就废话不多说了,大家还是直接看代码吧~ public static void main(String[] args) { &n
- 最近在研究dubbo时,发现了JAVA的SPI特性。SPI的全名为Service Provider Interface,是JDK内置的一种服
- 目录1、IP地址2、端口3、通信协议3.1 TCP/IP协议簇:实际上是一组协议3.2 TCP UDP对比3.3 TCP实现聊天3.4 TC
- 最近有一款2048的游戏非常火,本文将来介绍一下使用OGEngine游戏引擎开发游戏2048。OGEngine引擎是开源的,我们很容易找到,
- 在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现。1. 上传简单示例Jsp
- 原始Spring开发Person.java准备Person.java类:package com.jektong.spring;public
- 从功能上说,可以分为两部分,分布式功能和数据功能。分布式功能主要是节点集群及集群附属功能如restful借口、集群性能检测功能等,数据功能主
- AutoCompleteTextView是实现动态匹配输入内容的一种输入框(EditText),如输入“and”时,会提示“Android”
- 对象类型转换分为向上转型和向下转型(强制对象转型)。 向上转型是子对象向父对象转型的过程,例如猫类转换为动物类;向下转型是强制转型实现的,是
- telnet-client太费尽了,比ssh-client费尽的多,搞了一天,凑合能用,还得改。org.apache.commons.net
- 大家在使用 Intellij IDEA 的时候会经常遇到各种乱码问题,甚是烦扰。栈长也偶尔会用下IDEA,也有一些解决乱码的经验,我给大家总
- 目录一、基本使用二、常用的 APIImageLoaderImageRequestDisposable图片变换三、功能拓展Intercepto
- 前言我们一说到spring,可能第一个想到的是 IOC(控制反转) 和 AOP(面向切面编程)。没错,它们是spring的基石,得益于它们的
- 在日常开发的过程中我们经常会需要调用第三方组件或者数据库,有的时候可能会因为网络抖动或者下游服务抖动,导致我们某次查询失败。这种时候我们往往
- 前言终于来到了Maven的插件开发,其实Maven的插件并没有想象的那么难,刚开始讲Maven基础的时候就演示了一下JDK是如何打包的,Ma
- flutter组件的实现参考了react的设计理念,界面上所有的内容都是由组件构成,同时也有状态组件和无状态组件之分,这里简单介绍最基本的组
- 前言我们知道在 Java 中读取一些配置文件信息,是在开发中十分常用的要求。例如:这里我们使用 JDBC 实例:连接My
- Springboot整合RockerMQ1、maven依赖<dependencies> <!--
- 一、insert1.插入操作public class CRUDTests { @Autowired
- QueryWrapper 添加limit其实是在sql的最后加上 limit 相关的语句。QueryWrapper wrapper = ne