Spring Bean生命周期

Today we will look into Spring Bean Life Cycle. Spring Beans are the most important part of any Spring application. Spring ApplicationContext is responsible to initialize the Spring Beans defined in spring bean configuration file.

今天,我们将探讨Spring Bean生命周期。 Spring Bean是任何Spring应用程序中最重要的部分。 Spring ApplicationContext负责初始化spring bean配置文件中定义的Spring Bean。

Spring Bean生命周期 (Spring Bean Life Cycle)

spring bean life cycle

Spring Context is also responsible for injection dependencies in the bean, either through setter or constructor methods or by spring autowiring.


Spring上下文还负责注射的依赖 bean中,无论是通过制定者或构造方法或通过弹簧自动装配

Sometimes we want to initialize resources in the bean classes, for example creating database connections or validating third party services at the time of initialization before any client request. Spring framework provide different ways through which we can provide post-initialization and pre-destroy methods in a spring bean life cycle.

有时我们想初始化bean类中的资源,例如在任何客户端请求之前的初始化时创建数据库连接或验证第三方服务。 Spring框架提供了不同的方法,通过这些方法,我们可以在Spring bean生命周期中提供初始化后和销毁前的方法。

  1. By implementing InitializingBean and DisposableBean interfaces – Both these interfaces declare a single method where we can initialize/close resources in the bean. For post-initialization, we can implement InitializingBean interface and provide implementation of afterPropertiesSet() method. For pre-destroy, we can implement DisposableBean interface and provide implementation of destroy() method. These methods are the callback methods and similar to servlet listener implementations.

    This approach is simple to use but it’s not recommended because it will create tight coupling with the Spring framework in our bean implementations.

    InitializingBeanDisposableBean接口–这两个接口都声明了一个方法,我们可以在其中初始化/关闭bean中的资源。 对于后初始化,我们可以实现InitializingBean接口,并提供afterPropertiesSet()方法的实现。 对于破坏前,我们可以实现DisposableBean接口并提供destroy()方法的实现。 这些方法是回调方法,与servlet侦听器实现类似。

    这种方法易于使用,但不建议使用,因为它会在我们的bean实现中与Spring框架建立紧密的联系。

  2. Providing init-method and destroy-method attribute values for the bean in the spring bean configuration file. This is the recommended approach because of no direct dependency to spring framework and we can create our own methods.

    在spring bean配置文件中为bean提供init-methoddestroy-method属性值。 推荐这种方法,因为它不直接依赖于spring框架,因此我们可以创建自己的方法。

Note that both post-init and pre-destroy methods should have no arguments but they can throw Exceptions. We would also require to get the bean instance from the spring application context for these methods invocation.

请注意, post-init方法和销毁前方法均不应具有参数,但是它们可以引发Exceptions。 对于这些方法调用,我们还需要从spring应用程序上下文中获取bean实例。

Spring Bean生命周期– @ PostConstruct,@ PreDestroy注释 (Spring Bean Life Cycle – @PostConstruct, @PreDestroy Annotations)

Spring framework also support @PostConstruct and @PreDestroy annotations for defining post-init and pre-destroy methods. These annotations are part of javax.annotation package. However for these annotations to work, we need to configure our spring application to look for annotations. We can do this either by defining bean of type org.springframework.context.annotation.CommonAnnotationBeanPostProcessor or by context:annotation-config element in spring bean configuration file.

Spring框架还支持@PostConstruct@PreDestroy批注,用于定义后初始化和破坏前的方法。 这些注释是javax.annotation包的一部分。 但是,为了使这些注释起作用,我们需要配置spring应用程序以查找注释。 我们可以通过定义org.springframework.context.annotation.CommonAnnotationBeanPostProcessor类型的bean或通过spring bean配置文件中的context:annotation-config元素来实现。

Let’s write a simple Spring application to showcase the use of above configurations for spring bean life cycle management. Create a Spring Maven project in Spring Tool Suite, final project will look like below image.

让我们编写一个简单的Spring应用程序,以展示上述配置在Spring bean生命周期管理中的使用。 在Spring Tool Suite中创建一个Spring Maven项目,最终项目将如下图所示。

Spring Bean生命周期– Maven依赖关系 (Spring Bean Life Cycle – Maven Dependencies)

We don’t need to include any extra dependencies for configuring spring bean life cycle methods, our pom.xml file is like any other standard spring maven project.

我们不需要包含任何其他依赖项来配置Spring bean生命周期方法,我们的pom.xml文件就像其他任何标准的Spring Maven项目一样。

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.samples</groupId>
  <artifactId>SpringBeanLifeCycle</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>

		<!-- Generic properties -->
		<java.version>1.7</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>4.0.2.RELEASE</spring-framework.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

	</properties>
	
	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

	</dependencies>	
</project>

Spring Bean生命周期–模型类 (Spring Bean Life Cycle – Model Class)

Let’s create a simple java bean class that will be used in service classes.

让我们创建一个将在服务类中使用的简单Java bean类。

package com.journaldev.spring.bean;

public class Employee {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}

Spring Bean生命周期– InitializingBean,DisposableBean (Spring Bean Life Cycle – InitializingBean, DisposableBean)

Let’s create a service class where we will implement both the interfaces for post-init and pre-destroy methods.

让我们创建一个服务类,在该服务类中,我们将同时实现初始化后方法和销毁前方法的接口。

package com.journaldev.spring.service;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import com.journaldev.spring.bean.Employee;

public class EmployeeService implements InitializingBean, DisposableBean{

	private Employee employee;

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}
	
	public EmployeeService(){
		System.out.println("EmployeeService no-args constructor called");
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("EmployeeService Closing resources");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("EmployeeService initializing to dummy value");
		if(employee.getName() == null){
			employee.setName("Pankaj");
		}
	}
}

Spring Bean生命周期–自定义初始化后,销毁前 (Spring Bean Life Cycle – Custom post-init, pre-destroy)

Since we don’t want our services to have direct spring framework dependency, let’s create another form of Employee Service class where we will have post-init and pre-destroy spring life cycle methods and we will configure them in the spring bean configuration file.

由于我们不希望我们的服务具有直接的Spring框架依赖关系,因此让我们创建另一种形式的Employee Service类,其中将具有后初始化和销毁​​前的Spring生命周期方法,我们将在spring bean配置文件中对其进行配置。

package com.journaldev.spring.service;

import com.journaldev.spring.bean.Employee;

public class MyEmployeeService{

	private Employee employee;

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}
	
	public MyEmployeeService(){
		System.out.println("MyEmployeeService no-args constructor called");
	}

	//pre-destroy method
	public void destroy() throws Exception {
		System.out.println("MyEmployeeService Closing resources");
	}

	//post-init method
	public void init() throws Exception {
		System.out.println("MyEmployeeService initializing to dummy value");
		if(employee.getName() == null){
			employee.setName("Pankaj");
		}
	}
}

We will look into the spring bean configuration file in a bit. Before that let’s create another service class that will use @PostConstruct and @PreDestroy annotations.

我们将稍微研究一下spring bean配置文件。 在此之前,让我们创建另一个将使用@PostConstruct和@PreDestroy批注的服务类。

Spring Bean生命周期– @ PostConstruct,@ PreDestroy (Spring Bean Life Cycle – @PostConstruct, @PreDestroy)

Below is a simple class that will be configured as spring bean and for post-init and pre-destroy methods, we are using @PostConstruct and @PreDestroy annotations.

下面是一个将配置为spring bean的简单类,对于后初始化和销毁​​前方法,我们使用@PostConstruct和@PreDestroy批注。

package com.journaldev.spring.service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class MyService {

	@PostConstruct
	public void init(){
		System.out.println("MyService init method called");
	}
	
	public MyService(){
		System.out.println("MyService no-args constructor called");
	}
	
	@PreDestroy
	public void destory(){
		System.out.println("MyService destroy method called");
	}
}

Spring Bean生命周期–配置文件 (Spring Bean Life Cycle – Configuration File)

Let’s see how we will configure our beans in spring context file.

让我们看看如何在Spring上下文文件中配置我们的bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- Not initializing employee name variable-->
<bean name="employee" class="com.journaldev.spring.bean.Employee" />

<bean name="employeeService" class="com.journaldev.spring.service.EmployeeService">
	<property name="employee" ref="employee"></property>
</bean>

<bean name="myEmployeeService" class="com.journaldev.spring.service.MyEmployeeService"
		init-method="init" destroy-method="destroy">
	<property name="employee" ref="employee"></property>
</bean>

<!-- initializing CommonAnnotationBeanPostProcessor is same as context:annotation-config -->
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean name="myService" class="com.journaldev.spring.service.MyService" />
</beans>

Notice that I am not initializing employee name in it’s bean definition. Since EmployeeService is using interfaces, we don’t need any special configuration here.

注意,我没有在bean定义中初始化员工姓名。 由于EmployeeService使用接口,因此我们在这里不需要任何特殊配置。

For MyEmployeeService bean, we are using init-method and destroy-method attributes to let spring framework know our custom methods to execute.

对于MyEmployeeService bean,我们使用init-method和destroy-method属性来让spring框架知道要执行的自定义方法。

MyService bean configuration doesn’t have anything special, but as you can see that I am enabling annotation based configuration for this.

MyService bean配置没有什么特别的,但是您可以看到我正在为此启用基于注释的配置。

Our application is ready, let’s write a test program to see how different methods get executed.

我们的应用程序已准备就绪,让我们编写一个测试程序以查看如何执行不同的方法。

Spring Bean生命周期–测试程序 (Spring Bean Life Cycle – Test Program)

package com.journaldev.spring.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.spring.service.EmployeeService;
import com.journaldev.spring.service.MyEmployeeService;

public class SpringMain {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");

		System.out.println("Spring Context initialized");
		
		//MyEmployeeService service = ctx.getBean("myEmployeeService", MyEmployeeService.class);
		EmployeeService service = ctx.getBean("employeeService", EmployeeService.class);

		System.out.println("Bean retrieved from Spring Context");
		
		System.out.println("Employee Name="+service.getEmployee().getName());
		
		ctx.close();
		System.out.println("Spring Context Closed");
	}

}

When we run above test program, we get below output.

当我们在测试程序上方运行时,我们得到的输出如下。

Apr 01, 2014 10:50:50 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@c1b9b03: startup date [Tue Apr 01 22:50:50 PDT 2014]; root of context hierarchy
Apr 01, 2014 10:50:50 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
EmployeeService no-args constructor called
EmployeeService initializing to dummy value
MyEmployeeService no-args constructor called
MyEmployeeService initializing to dummy value
MyService no-args constructor called
MyService init method called
Spring Context initialized
Bean retrieved from Spring Context
Employee Name=Pankaj
Apr 01, 2014 10:50:50 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@c1b9b03: startup date [Tue Apr 01 22:50:50 PDT 2014]; root of context hierarchy
MyService destroy method called
MyEmployeeService Closing resources
EmployeeService Closing resources
Spring Context Closed

Spring Bean Life Cycle Important Points:

Spring Bean生命周期要点

  • From the console output it’s clear that Spring Context is first using no-args constructor to initialize the bean object and then calling the post-init method.

    从控制台输出中可以明显看出,Spring Context首先使用no-args构造函数初始化bean对象,然后调用post-init方法。
  • The order of bean initialization is same as it’s defined in the spring bean configuration file.

    bean初始化的顺序与在spring bean配置文件中定义的顺序相同。
  • The context is returned only when all the spring beans are initialized properly with post-init method executions.

    仅当使用post-init方法执行正确地初始化了所有spring bean时,才返回上下文。
  • Employee name is printed as “Pankaj” because it was initialized in the post-init method.

    员工名称被打印为“ Pankaj”,因为它是在post-init方法中初始化的。
  • When context is getting closed, beans are destroyed in the reverse order in which they were initialized i.e in LIFO (Last-In-First-Out) order.

    当关闭上下文时,将按照初始化时的相反顺序(即LIFO(后进先出)顺序)破坏bean。

You can uncomment the code to get bean of type MyEmployeeService and confirm that output will be similar and follow all the points mentioned above.

您可以取消注释该代码以获取MyEmployeeService类型的bean,并确认输出将是相似的并遵循上述所有要点。

Spring Aware接口 (Spring Aware Interfaces)

Sometimes we need Spring Framework objects in our beans to perform some operations, for example reading ServletConfig and ServletContext parameters or to know the bean definitions loaded by the ApplicationContext. That’s why spring framework provides a bunch of *Aware interfaces that we can implement in our bean classes.

有时,我们需要在bean中使用Spring Framework对象来执行某些操作,例如,读取ServletConfig和ServletContext参数或了解ApplicationContext加载的bean定义。 这就是为什么spring框架提供了一堆* Aware接口,我们可以在bean类中实现这些接口。

org.springframework.beans.factory.Aware is the root marker interface for all these Aware interfaces. All of the *Aware interfaces are sub-interfaces of Aware and declare a single setter method to be implemented by the bean. Then spring context uses setter-based dependency injection to inject the corresponding objects in the bean and make it available for our use.

org.springframework.beans.factory.Aware是所有这些Aware接口的根标记接口。 所有* Aware接口都是Aware的子接口,它们声明要由Bean实现的单个setter方法。 然后,Spring上下文使用基于setter的依赖项注入将相应的对象注入Bean中,并使其可供我们使用。

Spring Aware interfaces are similar to servlet listeners with callback methods and implementing observer design pattern.

Spring Aware接口类似于Servlet侦听器,具有回调方法和实现观察器设计模式

Some of the important Aware interfaces are:

一些重要的Aware接口是:

  • ApplicationContextAware – to inject ApplicationContext object, example usage is to get the array of bean definition names.

    ApplicationContextAware –注入ApplicationContext对象,示例用法是获取bean定义名称的数组。
  • BeanFactoryAware – to inject BeanFactory object, example usage is to check scope of a bean.

    BeanFactoryAware –注入BeanFactory对象,示例用法是检查bean的范围。
  • BeanNameAware – to know the bean name defined in the configuration file.

    BeanNameAware –了解配置文件中定义的Bean名称。
  • ResourceLoaderAware – to inject ResourceLoader object, example usage is to get the input stream for a file in the classpath.

    ResourceLoaderAware –注入ResourceLoader对象,示例用法是获取类路径中文件的输入流。
  • ServletContextAware – to inject ServletContext object in MVC application, example usage is to read context parameters and attributes.

    ServletContextAware –在MVC应用程序中注入ServletContext对象,示例用法是读取上下文参数和属性。
  • ServletConfigAware – to inject ServletConfig object in MVC application, example usage is to get servlet config parameters.

    ServletConfigAware –在MVC应用程序中注入ServletConfig对象,示例用法是获取servlet配置参数。

Let’s see these Aware interfaces usage in action by implementing few of them in a class that we will configure as spring bean.

通过在我们将配置为Spring Bean的类中实现其中的少数几个,让我们看看这些Aware接口的用法。

package com.journaldev.spring.service;

import java.util.Arrays;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;

public class MyAwareService implements ApplicationContextAware,
		ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
		BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware {

	@Override
	public void setApplicationContext(ApplicationContext ctx)
			throws BeansException {
		System.out.println("setApplicationContext called");
		System.out.println("setApplicationContext:: Bean Definition Names="
				+ Arrays.toString(ctx.getBeanDefinitionNames()));
	}

	@Override
	public void setBeanName(String beanName) {
		System.out.println("setBeanName called");
		System.out.println("setBeanName:: Bean Name defined in context="
				+ beanName);
	}

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		System.out.println("setBeanClassLoader called");
		System.out.println("setBeanClassLoader:: ClassLoader Name="
				+ classLoader.getClass().getName());
	}

	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		System.out.println("setResourceLoader called");
		Resource resource = resourceLoader.getResource("classpath:spring.xml");
		System.out.println("setResourceLoader:: Resource File Name="
				+ resource.getFilename());
	}

	@Override
	public void setImportMetadata(AnnotationMetadata annotationMetadata) {
		System.out.println("setImportMetadata called");
	}

	@Override
	public void setEnvironment(Environment env) {
		System.out.println("setEnvironment called");
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println("setBeanFactory called");
		System.out.println("setBeanFactory:: employee bean singleton="
				+ beanFactory.isSingleton("employee"));
	}

	@Override
	public void setApplicationEventPublisher(
			ApplicationEventPublisher applicationEventPublisher) {
		System.out.println("setApplicationEventPublisher called");
	}

}

Spring * Aware示例配置文件 (Spring *Aware Example Configuration File)

Very simple spring bean configuration file.

非常简单的spring bean配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

<bean name="employee" class="com.journaldev.spring.bean.Employee" />

<bean name="myAwareService" class="com.journaldev.spring.service.MyAwareService" />

</beans>

Spring*感知测试程序 (Spring *Aware Test Program)

package com.journaldev.spring.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.spring.service.MyAwareService;

public class SpringAwareMain {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-aware.xml");

		ctx.getBean("myAwareService", MyAwareService.class);
		
		ctx.close();
	}

}

Now when we execute above class, we get following output.

现在,当我们执行上述类时,将得到以下输出。

Apr 01, 2014 11:27:05 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@60a2f435: startup date [Tue Apr 01 23:27:05 PDT 2014]; root of context hierarchy
Apr 01, 2014 11:27:05 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-aware.xml]
setBeanName called
setBeanName:: Bean Name defined in context=myAwareService
setBeanClassLoader called
setBeanClassLoader:: ClassLoader Name=sun.misc.Launcher$AppClassLoader
setBeanFactory called
setBeanFactory:: employee bean singleton=true
setEnvironment called
setResourceLoader called
setResourceLoader:: Resource File Name=spring.xml
setApplicationEventPublisher called
setApplicationContext called
setApplicationContext:: Bean Definition Names=[employee, myAwareService]
Apr 01, 2014 11:27:05 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@60a2f435: startup date [Tue Apr 01 23:27:05 PDT 2014]; root of context hierarchy

Console output of the test program is simple to understand, I won’t go into much detail about that.

测试程序的控制台输出很容易理解,我不会对此进行详细介绍。

That’s all for the Spring Bean Life Cycle methods and injecting framework specific objects into the spring beans. Please download sample project from below link and analyze it to learn more about them.

这就是Spring Bean生命周期方法的全部内容,并将特定于框架的对象注入Spring Bean。 请从下面的链接下载示例项目并对其进行分析以了解有关它们的更多信息。

翻译自: https://www.journaldev.com/2637/spring-bean-life-cycle

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值