Bean的生命周期,尤其是Bean从实例化到可以使用,过程较为复杂,所以建议自己coding一遍来加深理解。
该周期中涵盖了Spring Aware接口,Spring PostProcessor后置处理器等等,首次接触时可能会觉得晦涩难懂,结合应用场景更有助于理解。
Spring容器将对其所管理的对象全部给予统一的生命周期管理,这些被管理的对象完全摆脱了原来那种“new完后被使用,脱离作用域后即被回收”的命运。
Q: Bean在什么时候会被创建?
A: 容器启动之后,并不会马上就实例化相应的bean定义。容器现在仅仅拥有所有对象的BeanDefinition来保存实例化阶段将要用的必要信息。只有当请求方通过BeanFactory的getBean()方法来请求某个对象实例的时候,才有可能触发Bean实例化阶段的活动。BeanFactory的getBean()方法可以被客户端对象显式调用,也可以在容器内部隐式地被调用。隐式调用有如下两种情况:
之所以说getBean()方法是有可能触发Bean实例化阶段的活动,是因为只有当对应某个bean定义的getBean()方法第一次被调用时,不管是显式的还是隐式的,Bean实例化阶段的活动才会被触发,第二次被调用则会直接返回容器缓存的第一次实例化完的对象实例(prototype类型bean除外)。当getBean()方法内部发现该bean定义之前还没有被实例化之后,会通过createBean()方法来进行具体的对象实例化.
scope用来声明容器中的对象所应该处的限定场景或者说该对象的存活时间,即容器在对象进入其相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁Spring 的 IoC 容器这些对象。
如果你不指定bean的scope,singleton便是容器默认的scope.
标记为singleton的bean是由容器来保证这种类型的bean在同一个容器中只存在一个共享实例;而Singleton模式则是保证在同一个Classloader中只存在一个这种类型的实例。
另外三种scope类型,即request、session和global session类型,只有在支持Web应用的ApplicationContext中才能使用这三个scope。
Q: Spring中的单例模式是否时线程安全的?
A: 关于单例bean的多线程行为,Spring框架没有做任何事情。开发人员有责任处理单例bean的并发问题和线程安全问题。 实际上,大多数Spring bean都没有可变状态,因此非常简单。但是如果你的bean具有可变状态,那么你需要确保线程安全。解决此问题最简单明了的方法是将可变bean的bean范围从“singleton”更改为“prototype".
org.springframework.beans.factory.Aware
使得自定义Bean可以识别利用Spring容器的资源,比如,
BeanNameAware.setBeanName(String)
,可以在Bean中得到它在IOC容器中的Bean的实例的名字。BeanFactoryAware.setBeanFactory(BeanFactory)
,可以在Bean中得到Bean所在的IOC容器,从而直接在Bean中使用IOC容器的服务。ApplicationContextAware.setApplicationContext(ApplicationContext)
,可以在Bean中得到Bean所在的应用上下文,从而直接在Bean中使用上下文的服务。如非必要,Spring官方不推荐自定义Bean实现Aware接口,这会增加代码与Spring 框架的耦合性。
BeanPostProcessor是存在于对象实例化阶段,而BeanFactoryPostProcessor则是存在于容器启动阶段
Spring Aware和PostProcessor都是提供了用户利用Spring IoC添加业务逻辑进一步定制Bean。
public class MyBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanClassLoaderAware,
InitializingBean, DisposableBean {
private String name;
private String description;
public MyBean() {
System.out.println("**MyBean** construct.");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("**MyBean** BeanClassLoaderAware.setBeanClassLoader: " + classLoader.getClass());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("**MyBean** BeanFactoryAware.setBeanFactory: " + beanFactory.getClass());
}
@Override
public void setBeanName(String s) {
System.out.println("**MyBean** BeanNameAware.getBeanName: " + s);
}
@Override
public void destroy() throws Exception {
System.out.println("**MyBean** DisposableBean.destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("**MyBean** InitializingBean.afterPropertiesSet");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("**MyBean** ApplicationContextAware.setApplicationContext");
}
@Override
protected void finalize() throws Throwable {
System.out.println("**MyBean** MyBean finalized.");
}
@PostConstruct
public void springPostConstruct() {
System.out.println("**MyBean** @PostConstruct");
}
// xml文件中的init-method
public void myInitMethod() {
System.out.println("**MyBean** init-method");
}
@PreDestroy
public void springPreDestroy() {
System.out.println("**MyBean** @PreDestroy");
}
// xml文件中的destroy-method
public void mydestroyMethod() {
System.out.println("**MyBean** destory-method");
}
@Autowired
public void setName(String name) {
this.name = name;
System.out.println("**MyBean** setName");
}
@Autowired
public void setDescription(String description) {
this.description = description;
System.out.println("**MyBean** setDescription");
}
@Override
public String toString() {
return "MyBean{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
'}';
}
}
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
super();
System.out.println("[MyBeanFactoryPostProcessor] constructor");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("[MyBeanFactoryPostProcessor] postProcessBeanFactory");
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
super();
System.out.println("[MyBeanPostProcessor] constructor.");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("[MyBeanPostProcessor] postProcessBeforeInitialization: " + bean.getClass() + ": " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("[MyBeanPostProcessor] postProcessAfterInitialization: " + bean.getClass() + ": " + beanName);
return bean;
}
}
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
public MyInstantiationAwareBeanPostProcessor() {
super();
System.out.println("[MyInstantiationAwareBeanPostProcessor] constructor.");
}
// 接口方法、实例化Bean之前调用
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("[MyInstantiationAwareBeanPostProcessor] postProcessBeforeInstantiation");
return null;
}
// 接口方法、实例化Bean之前调用
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("[MyInstantiationAwareBeanPostProcessor] postProcessAfterInstantiation");
return true;
}
// 接口方法、设置某个属性时调用
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
System.out.println("[MyInstantiationAwareBeanPostProcessor] postProcessPropertyValues");
// 注意返回结果,否则会无法正确Bean的属性
return pvs;
}
}
public class LifeCycleApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("lifecycle.xml");
System.out.println("[Application] before get bean");
MyBean bean = (MyBean) context.getBean("myBean");
System.out.println("[Application] after get bean");
System.out.println(bean);
((ClassPathXmlApplicationContext) context).registerShutdownHook();
}
}
lifecycle.xml:
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example.LifeCycle"/>
<bean id="myBean" class="com.example.LifeCycle.MyBean" init-method="myInitMethod"
destroy-method="mydestroyMethod">
bean>
<bean class="com.example.LifeCycle.MyBeanPostProcessor"/>
<bean class="com.example.LifeCycle.MyBeanFactoryPostProcessor"/>
<bean class="com.example.LifeCycle.MyInstantiationAwareBeanPostProcessor"/>
beans>
运行结果:
...
[MyBeanFactoryPostProcessor] constructor
...
MyBeanFactoryPostProcessor] postProcessBeanFactory
...
[MyBeanPostProcessor] constructor
...
[MyInstantiationAwareBeanPostProcessor] constructor
[MyInstantiationAwareBeanPostProcessor] constructor
...
16:18:06.149 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'myBean'
**MyBean** construct.
16:18:06.154 [main] DEBUG org.springframework.context.annotation.CommonAnnotationBeanPostProcessor - Found init method on class [com.example.LifeCycle.MyBean]: public void com.example.LifeCycle.MyBean.springPostConstruct()
16:18:06.154 [main] DEBUG org.springframework.context.annotation.CommonAnnotationBeanPostProcessor - Found destroy method on class [com.example.LifeCycle.MyBean]: public void com.example.LifeCycle.MyBean.springPreDestroy()
16:18:06.154 [main] DEBUG org.springframework.context.annotation.CommonAnnotationBeanPostProcessor - Registered init method on class [com.example.LifeCycle.MyBean]: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement@21a44a0a
16:18:06.154 [main] DEBUG org.springframework.context.annotation.CommonAnnotationBeanPostProcessor - Registered destroy method on class [com.example.LifeCycle.MyBean]: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement@5caf49c4
16:18:06.176 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Registered injected element on class [com.example.LifeCycle.MyBean]: AutowiredMethodElement for public void com.example.LifeCycle.MyBean.setDescription(java.lang.String)
16:18:06.176 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Registered injected element on class [com.example.LifeCycle.MyBean]: AutowiredMethodElement for public void com.example.LifeCycle.MyBean.setName(java.lang.String)
...
[MyInstantiationAwareBeanPostProcessor] postProcessAfterInstantiation
[MyInstantiationAwareBeanPostProcessor] postProcessPropertyValues
...
[MyInstantiationAwareBeanPostProcessor] postProcessAfterInstantiation
[MyInstantiationAwareBeanPostProcessor] postProcessPropertyValues
16:18:06.177 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'myBean': AutowiredMethodElement for public void com.example.LifeCycle.MyBean.setDescription(java.lang.String)
16:18:06.177 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'myBean': AutowiredMethodElement for public void com.example.LifeCycle.MyBean.setName(java.lang.String)
*MyBean** setName
**MyBean** setDescription
**MyBean** BeanNameAware.getBeanName: myBean
**MyBean** BeanClassLoaderAware.setBeanClassLoader: class sun.misc.Launcher$AppClassLoader
**MyBean** BeanFactoryAware.setBeanFactory: class org.springframework.beans.factory.support.DefaultListableBeanFactory
**MyBean** ApplicationContextAware.setApplicationContext
[MyBeanPostProcessor] postProcessBeforeInitialization: class com.example.LifeCycle.MyBean: myBean
...
**MyBean** init-method
...
MyBean{name='Gigi', description='description'}
...
**MyBean** @PreDestroy
**MyBean** DisposableBean.destroy
**MyBean** destory-method
不建议使用InitializingBean, DisposableBean,因为这个会增加代码与Spring框架的耦合性。
@PostConstruct,@PreDestroy是JavaX的标准,而非Java,Spring定义的注解,使用时应该注意。
将Bean从Spring IoC中移除之前需要释放持有的资源,建议在destroy-method中写释放资源的代码。
了解Bean的生命周期有利于我们根据业务需要对Bean进行相关的拓展工作。
举个例子,在Bean初始化前希望用户名和密码。倘若将这些信息硬编码到工厂代码中显然是不安全的,一般地,公司会有一个统一的密码存储服务,通过调用开放的API获取用户名和密码。此时,我们可以在Bean的init-method中加入这样的逻辑:调用公司的密码存储服务API获取用户名和密码,加载至Bean的相关字段中。
再举个例子,在Bean被销毁之前,释放Bean与数据库的连接,那么我们可以把释放数据库连接这段逻辑放到destroy-method中。
Ref: