Spring(09)——bean生命周期回调方法

简介: 9 生命周期回调方法 对于Spring bean来讲,我们默认可以指定两个生命周期回调方法。一个是在ApplicationContext将bean初始化,包括注入对应的依赖后的回调方法;另一个是在ApplicationContext准备销毁之前的回调方法。

9 生命周期回调方法

对于Spring bean来讲,我们默认可以指定两个生命周期回调方法。一个是在ApplicationContextbean初始化,包括注入对应的依赖后的回调方法;另一个是在ApplicationContext准备销毁之前的回调方法。要实现这种回调主要有三种方式:实现特定的接口、在XML配置文件中指定回调方法和使用JSR-250标准的注解。

9.1 实现特定接口

针对bean初始化后的回调和ApplicationContext销毁前的回调,Spring分别为我们了提供了InitializingBeanDisposableBean接口供用户实现,这样Spring在需要进行回调时就会调用对应接口提供的回调方法。

9.1.1 InitializingBean

InitializingBean是用来定义ApplicationContext在完全初始化一个bean以后需要需要回调的方法的,其中只定义了一个afterPropertiesSet()方法。如其名称所描述的那样,该方法将在ApplicationContext将一个bean完全初始化,包括将对应的依赖项都注入以后才会被调用。InitializingBean的完全定义如下。

public interface InitializingBean {

	void afterPropertiesSet() throws Exception;

}

由于InitializingBeanafterPropertiesSet()方法会在依赖项都进行注入以后再回调,所以该方法通常会用来检查必要的依赖注入,以使我们能够在bean被初始化时就发现其中的错误,而不是在很长时间使用以后才发现。如果你去看Spring的源码,你就会发现源码中有很多InitializingBean的使用,而且基本都是用来检查必要的依赖项是否为空的。

public class Hello implements InitializingBean {
	
	private World world;
	
	/**
	 * 该方法将在当前bean被完全初始化后被调用
	 */
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(world, "world should not be null.");
	}

	public void setWorld(World world) {
		this.world = world;
	}
	
}

9.1.2 DisposableBean

DisposableBean是用来定义在ApplicationContext销毁之前需要回调的方法的。DisposableBean接口中只定义了一个destroy()方法,在ApplicationContext被销毁前,Spring将依次调用bean容器中实现了DisposableBean接口的destroy()方法。所以,我们可以通过实现该接口的destroy()方法来达到在ApplicationContext销毁前释放某些特定资源的目的。

public interface DisposableBean {

	void destroy() throws Exception;

}

Spring的源码中,也有很多实现了DisposableBean接口的类,如我们熟悉的ApplicationContext实现类、SingleConnectionDataSource等。

9.2 在XML中配置回调方法

XML配置文件中通过bean元素定义一个bean时,我们可以通过bean元素的init-method属性和destroy-method属性来指定当前bean在初始化以后和ApplicationContext销毁前的回调方法。需要注意的是所指定的回调方法必须是没有参数的。
通过init-method属性来指定初始化方法时所对应的方法必须是该bean中所拥有的方法,所以首先我们需要在对应的bean中定义对应的初始化方法,这里假设我们需要在bean中定义一个init()方法作为该bean的初始化方法,那么我们可以对我们的bean进行类似如下定义。

public class Hello {
	
	private World world;
	
	/**
	 * 该方法将被用来作为初始化方法,在当前bean被完全初始化后被调用
	 */
	public void init() {
		Assert.notNull(world, "world should not be null.");
	}

	public void setWorld(World world) {
		this.world = world;
	}
	
}

接下来就是在XML配置文件中定义该bean时通过init-method属性定义对应的初始化方法为init()方法,init-method属性的属性值就对应初始化方法的名称,所以我们的bean应该是如下定义。

	<bean name="world" class="com.app.World"/>
	<!-- 通过init-method属性指定初始化方法名称 -->
	<bean id="hello" class="com.app.Hello" init-method="init">
		<property name="world" ref="world"/>
	</bean>

init-methoddestroy-method的用法和配置等基本上都是一样的,所以对于使用destroy-method来指定ApplicationContext销毁前的回调方法的用法就不再赘述了。

如果我们的初始化方法或销毁方法的名称大都是一样的,在通过init-methoddestroy-method进行指定的时候我们就没有必要一个个bean都去指定了,Spring允许我们在最顶级的beans元素上指定默认的初始化后回调方法和销毁前的回调方法名称,这样对于没有指定init-methoddestroy-method的bean将默认将其中default-init-methoddefault-destroy-method属性值对应名称的方法(如果存在的话)视为初始化后的回调方法或销毁前的回调方法。这是通过default-init-methoddefault-destroy-method属性来定义的。

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
    default-init-method="init" default-destroy-method="destroy">
	
</beans>

以上表示定义默认的初始化后回调方法名称为init,默认的销毁前回调方法名称为destroy。
当定义了default-init-methoddefault-destroy-method以后,如果我们的某个bean对应的初始化后回调方法名称或销毁前的回调方法名称与默认定义的不一样,则我们可以在对应的bean上通过init-methoddestroy-method指定该bean自身的回调方法名称,即bean上定义的回调方法名称将会比默认定义拥有更高的优先级。

9.3 使用JSR-250标准的注解

关于bean的生命周期回调方法,Spring也会JSR-250标准注解做了支持,即在bean完全初始化后将回调使用@PostConstruct标注的方法,在销毁ApplicationContext前将回调使用@PreDestroy标注的方法。
针对之前的示例,如果我们现在把定义的bean定义成如下这样,即没有在bean上通过init-methoddestroy-method指定初始化方法和销毁方法。

	<bean name="world" class="com.app.World"/>
	<bean id="hello" class="com.app.Hello">
		<property name="world" ref="world"/>
	</bean>

当然,这里也不考虑全局性的init-methoddestroy-method方法,如果我们希望在id为“hello”的bean被初始化后回调其中的init()方法,在销毁前回调其中的destroy()方法,我们就可以通过@PostConstruct@PreDestroy进行如下定义。

public class Hello {
	
	private World world;
	
	/**
	 * 该方法将被用来作为初始化方法,在当前bean被完全初始化后被调用
	 */
	@PostConstruct
	public void init() {
		Assert.notNull(world, "world should not be null.");
	}
	
	@PreDestroy
	public void destroy() {
		System.out.println("---------destroy-----------");
	}

	public void setWorld(World world) {
		this.world = world;
	}
	
}

使用JSR-250标准指定初始化后的回调方法以及销毁前的回调方法时,如果我们希望将多个方法都作为对应的回调方法进行回调,则可以在多个方法上同时使用对应的注解进行标注,Spring将依次执行对应的方法。

public class Hello {
	
	private World world;

	@PostConstruct
	public void init() {
		System.out.println("-----------init-------------");
	}
	
	/**
	 * 该方法将被用来作为初始化方法,在当前bean被完全初始化后被调用
	 */
	@PostConstruct
	public void init2() {
		Assert.notNull(world, "world should not be null.");
	}
	
	@PreDestroy
	public void destroy() {
		System.out.println("------------destroy----------------");
	}
	
	@PreDestroy
	public void destroy2() {
		System.out.println("---------destroy2-----------");
	}

	public void setWorld(World world) {
		this.world = world;
	}
	
}

9.4 混合使用三种方式

Spring允许我们混合使用上述介绍的三种方式来指定对应的回调方法。当对于同一个bean使用三种方式指定了同一个方法作为初始化后的回调方法或销毁前的回调方法,则对应的回调方法只会被执行一次。然而,当对于同一个bean使用两种或三种方式指定的回调方法不是同一个方法时,Spring将依次执行使用不同的方式指定的回调方法。对于初始化后的回调方法而言,具体规则如下:

  • 使用@PostConstruct标注的方法。
  • 实现InitializingBean接口后的回调方法afterPropertiesSet()方法。
  • 通过init-method或default-init-method指定的方法。

对于销毁前的回调方法而言,其规则是一样的:

  • 使用@PreDestroy标注的方法。
  • 实现DisposableBean接口后的回调方法destroy()方法。
  • 通过destroy-method或default-destroy-method指定的方法。

(注:本文是基于Spring4.1.0所写)

 

目录
相关文章
|
13天前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
50 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
3天前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
13天前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
42 1
|
15天前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
14 1
|
1月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
10天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
54 2
|
2月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
10天前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
22 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
3月前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。
|
15天前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
101 2