一、摘要
本文主要介绍Spring Bean管理的IOC容器部分:BeanFactory和ApplicationContext,以及Bean如何创建、销毁,如何通过InitializingBean、BeanPostProcessor等接口或init-method、destroy-method等bean自身方法进行生命周期管理。
二、IOC容器
简单理解,BeanFactory和ApplicationContext是Spring IOC两大容器。其中BeanFactory作为最顶层的一个接口类,亦是IOC容器的核心接口,它定义了IOC容器的基本功能规范,DefaultListableBeanFactory是其默认实现类,最常用一个方法就是getBean。ApplicationContext接口扩展了BeanFactory,还提供了AOP、国际化处理、事件传播及不同层次的context实现 (如针对web应用的WebApplicationContext)。
1、先看看两者的简单使用方法
1)xml配置文件 helloWorldBean.xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.marcus.spring.beans.HelloWorldBean">
<property name="message" value="Hello World!"/>
</bean>
</beans>
2)Java代码
package com.marcus.spring.beans;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
* BeanApp.
*/
public class BeanApp {
public static void main(String[] args) {
// beanfactory
beanFactory();
//
applicationContext();
}
private static void beanFactory() {
Resource resource=new ClassPathResource("helloWorldBean.xml");
BeanFactory fa=new DefaultListableBeanFactory();
BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) fa);
bdr.loadBeanDefinitions(resource);
//
System.out.println("get bean by beanFactory.");
HelloWorldBean helloWorld = fa.getBean("helloWorld", HelloWorldBean.class);
helloWorld.getMessage();
System.out.println(helloWorld);
helloWorld.setMessage("tmd singleton!");
//验证是否单例
helloWorld = fa.getBean("helloWorld", HelloWorldBean.class);
helloWorld.getMessage();
System.out.println(helloWorld);
}
private static void applicationContext() {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("helloWorldBean.xml");
System.out.println("=================================================");
System.out.println("get bean by applicationContext.");
HelloWorldBean helloWorld = context.getBean("helloWorld", HelloWorldBean.class);
helloWorld.getMessage();
System.out.println(helloWorld);
helloWorld.setMessage("tmd singleton!");
//验证是否单例
helloWorld = context.getBean("helloWorld", HelloWorldBean.class);
helloWorld.getMessage();
System.out.println(helloWorld);
context.close();
}
}
3) 控制台输出
get bean by beanFactory.
Your Message : Hello World!
com.marcus.spring.beans.HelloWorldBean@64616ca2
Your Message : tmd singleton!
com.marcus.spring.beans.HelloWorldBean@64616ca2
=================================================
get bean by applicationContext.
Your Message : Hello World!
com.marcus.spring.beans.HelloWorldBean@5bcab519
Your Message : tmd singleton!
com.marcus.spring.beans.HelloWorldBean@5bcab519
2、两者区别
1)两者Bean加载方式不同
BeanFactroy采用的是延迟加载形式来注入Bean的,读取配置文件加载的是Bean定义,只有在使用某个Bean时(调用getBean()),才对该Bean进行加载实例化。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有Bean。相对于基本的BeanFactory,ApplicationContext唯一的不足是耗内存,当应用程序配置Bean较多时,程序启动较慢。
2)自动化程度不一样
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但BeanFactory需要手动注册,而ApplicationContext则是自动注册。比如BeanPostProcessor,ApplicationContext在xml文件中配置即可,而BeanFactory则需手动编写代码。假设:TestBeanPostProcessor是BeanPostProcessor的实现类,那么:
- ApplicationContext:
只要在xml中配置 bean class=”TestBeanPostProcessor”,- BeanFactory则需要手动编写代码:
factory.addBeanPostProcessor(new TestBeanPostProcessor());
3)功能丰富程度不一样
ApplicationContext扩展了BeanFactory,较BeanFactory有更多功能:
- 国际化(MessageSource)
- 访问资源,如URL和文件(ResourceLoader)
- 载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定的层次,比如WebApplicationContext
- 事件传播,自定义事件(ApplicationEventPublisher)
- AOP(拦截器)
3、两者使用场景
BeanFactory主要面对spring框架的基础设施,面对spring自身。而ApplicationContext 主要面对spring开发者,本文后续部分都使用ApplicationContext管理Bean。
三、Bean生命周期
理解Spring bean的生命周期很容易,实例化–>初始化–>销毁。当一个bean被实例化时,它可能需要执行一些初始化使它转换成可用状态;同样,当bean不再需要,从容器中移除时,可能需要做一些清理工作。
1、跟生命周期相关的方法、接口说明
1)Bean自身方法——配置文件
init-method/destroy-method,通过配置文件bean定义中添加相应属性指定相应执行方法,或默认的全局初始化或销毁方法:default-init-method=”init”等。
bean init/destroy方法
<bean id=”xxx” class=”xxx” init-method=”init” destroy-method=”destroy” />
=============================
默认的初始化或销毁方法
<beans …
default-init-method=”init” default-destroy-method=”destroy”>
2)Bean自身方法——注解
@PostConstruct,@PreDestroy
3)Bean级生命周期接口
- InitializingBean: void afterPropertiesSet() throws Exception;
- DiposableBean: void destroy() throws Exception;
- BeanNameAware: void setBeanName(String name);
- BeanFactoryAware: void setBeanFactory(BeanFactory beanFactory);
4)容器级生命周期接口方法
包括InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现(前者继承自后者),即所谓的后置处理器。
5)工厂后处理器接口方法
这些方法也是容器级别的,例如BeanFactoryPostProcessor、 CustomAutowireConfigurer等。
2、Bean生命周期相关代码实例
1)xml配置文件 beanLifeCycle.xml
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean id="helloWorld" class="com.marcus.spring.beans.HelloWorldLifeCycle"
init-method="beanInit" destroy-method="beanDestroy" >
<property name="message" value="Hello World!"/>
</bean>
<bean id="beanPostProcessorTest" class="com.marcus.spring.beans.BeanPostProcessorTest" />
</beans>
注意:因为bean使用了@PostConstruct,所以配置文件添加了context:annotation-config
2)java bean 代码
package com.marcus.spring.beans;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* HelloWorld生命周期Bean.
* @author marcus
*
*/
public class HelloWorldLifeCycle implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean {
private String message;
public void setMessage(String message) {
this.message = message;
}
public void getMessage() {
System.out.println("bean getMessage(), message = " + message);
}
// DisposableBean
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean->destroy() executed!");
}
// InitializingBean
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean->afterPropertiesSet() executed!");
}
// BeanFactoryAware
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware->setBeanFactory(), 此时factory = " + beanFactory);
}
// BeanNameAware
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware->setBeanName(), 此时name = " + name);
}
public void beanInit() {
System.out.println("bean init-method: beanInit() executed.");
}
public void beanDestroy() {
System.out.println("bean destroy-method: beanDestroy() executed.");
}
@PostConstruct
public void beanPostInit() {
System.out.println("Bean @PostConstruct beanPostInit executed.");
}
@PreDestroy
public void beanPreDestroy() {
System.out.println("Bean @PreDestroy beanPreDestroy executed.");
}
}
3) 测试类 java 代码
public static void main(String[] args) {
beanLifeCycle();
}
private static void beanLifeCycle() {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("beanLifeCycle.xml");
HelloWorldLifeCycle helloWorld = context.getBean("helloWorld", HelloWorldLifeCycle.class);
helloWorld.getMessage();
System.out.println("bean ID: " + helloWorld);
context.close();
}
注意:为了触发@PreDestroy或destroy-method或DisposableBean,使用了AbstractApplicationContext,并close()。
4) 控制台输出
BeanNameAware->setBeanName(), 此时name = helloWorld
BeanFactoryAware->setBeanFactory(), 此时factory = org.springframework.beans.factory.support.DefaultListableBeanFactory@366e2eef: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,helloWorld,beanPostProcessorTest,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
BeanPostProcessor->postProcessBeforeInitialization : helloWorld
Bean @PostConstruct beanPostInit executed.
InitializingBean->afterPropertiesSet() executed!
bean init-method: beanInit() executed.
BeanPostProcessor->postProcessAfterInitialization : helloWorld
bean getMessage(), message = Hello World!
bean ID: com.marcus.spring.beans.HelloWorldLifeCycle@1b68ddbd
Bean @PreDestroy beanPreDestroy executed.
DisposableBean->destroy() executed!
bean destroy-method: beanDestroy() executed.
3、Bean生命周期总结
1)常用使用方式
- 通过xml配置实现的bean自身的init、destroy方法;
- 通过java代码注解实现的@PostConstruct,@PreDestroy方法;
- BeanPostProcessor
2)@PostConstruct InitializingBean init-method执行顺序问题
通过上述代码我们可以推断出,3者执行顺序为:@PostConstruct > InitializingBean > init-method,原因:
1) BeanPostProcessor的postProcessBeforeInitialization是在afterPropertiesSet和init-method之前执被调用;
2) @PostConstruct背后实现原理是CommonAnnotationBeanPostProcessor,本质上就是BeanPostProcessor,所以@PostConstruct在其它2个方法前执行;
3)至于InitializingBean,init-method则是bean构建完后,spring先会判断bean是否实现InitializingBean,如果有则调用afterPropertiesSet方法,然后判断是否指定了init-method,如果有则通过反射调用指定方法。