1.6. Customizing the Nature of a Bean
The Spring Framework provides a number of interfaces you can use to customize the nature of a bean
Spring提供了非常多的接口,让用户可以自定义the nature of a bean(the nature of a bean,用英文描述起来感觉非常棒,但是中文实在不知道怎么翻译,翻译成bean的本性?bean的特性?怎么翻译都觉得尬。本文还是用英文称之为bean nature吧)。
1.6.1. Lifecycle Callbacks
bean生命周期简单说就是对象从生成到销毁的这个过程,其间如果用户想要插入相关操作,Spring通过提供相应的生命周期管理方法来达到这个目的。bean生命周期管理的意义:举个例子,假设在bean销毁时必须执行某些释放资源的操作,通过实现Spring给定的接口,Spring就会在bean销毁时自动调用相关操作,而不需要用户去显示调用。
Initialization and Destruction Callbacks
本节提供四种方式用来控制bean的生命周期,针对初始化和销毁这两个方法回调:
- 继承接口InitializingBean, DisposableBean,分别实现初始化方法afterPropertiesSet()和销毁方法destroy()
- 自定义方法名,通过xml指定方法名称
- 使用注解@PostConstruct和@PreDestroy,由于本节还未涉及注解方法,此方法暂不做示例,留待后续章节
- 跟自定义方法名类似,只是变成xml的全局配置,配置在xml的beans元素中,优先级低
继承接口示例:
public class InterfaceBean implements InitializingBean, DisposableBean {
public void destroy() throws Exception {
System.out.println("InterfaceBean destroy.");
}
public void afterPropertiesSet() throws Exception {
System.out.println("InterfaceBean Initializing.");
}
}
自定义方法名配置示例:
<bean id="xmlBean" class="examples.XmlBean" init-method="init" destroy-method="cleanup"/>
package examples;
public class XmlBean {
public void init() {
System.out.println("XmlBean init.");
}
public void cleanup() {
System.out.println("XmlBean cleanup.");
}
}
全局方法名配置示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans
default-init-method="init"
default-destroy-method="destroy">
</beans>
Startup and Shutdown Callbacks
前面演示了对象的初始化和销毁方法如何在Spring中实现,对于普通对象,可能初始化和销毁就足够了,但是对于类似服务这种对象,它会存在启动和停止操作,同样可以把这两种操作当做生命周期来管理。
Spring提供了两个接口,分别是Lifecycle和SmartLifecycle,需要启停的bean可以继承这两个接口。这两个接口的区别在于:Lifecycle必须用户自己调用start和stop方法,而SmartLifecycle可以支持在Container初始化完成后自动调用start方法(实现isAutoStartup(),返回true);SmartLifecycle通过继承Phased接口实现了启动的优先级,这块在后面说明。
Lifecycle:
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
SmartLifecycle:
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
只要Spring Container中管理的bean实现了这两个接口,当ApplicationContext调用其start和stop方法,所有被它管理的bean都会调用相应接口的回调。ApplicationContext本质是交给了代理类LifecycleProcessor执行相关方法,LifecycleProcessor是个接口,它的Spring缺省实现是DefaultLifecycleProcessor。
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
SmartLifecycle支持设置启动停止优先级,当A和B都实现了SmartLifecycle接口,SmartLifecycle的父接口Phased支持设置启动停止优先级:
public interface Phased {
int getPhase();
}
getPhase返回值越小,优先级越高,返回值越大,优先级越低。假设A和B继承SmartLifecycle,A的getPhase()返回值为-1,B的getPhase()返回值为1,那么A的start方法就会先于B调用,这样在对启动顺序有要求的情况下,可以有序的启动。而实现了Lifecycle接口的对象,优先级默认为0,相当于实现SmartLifecycle接口,但是getPhase()返回值为0。在调用stop方法时,优先级则相反。
Lifecycle接口的isRunning方法
isRunning方法的返回值会影响start和stop方法的调用,当调用start方法前 ,会检查isRunning返回值,如果为false,才会调用start;当调用stop方法前 ,也会检查isRunning返回值,如果为true,才会调用stop。
Shutting Down the Spring IoC Container Gracefully in Non-Web Applications
如何优雅的关闭Spring IoC Container(非web应用),很简单,调用registerShutdownHook方法即可,之后就会异步的执行每个bean的stop方法和destroy方法了:
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
}
1.6.2. ApplicationContextAware and BeanNameAware
ApplicationContextAware接口:
public interface ApplicationContextAware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
BeanNameAware接口:
public interface BeanNameAware {
void setBeanName(String name) throws BeansException;
}
Spring容器中管理的bean如果实现了上述两个接口,就可以通过这两个方法获取到ApplicationContext和BeanName的引用,进而做比较复杂的容器管理操作,当然,官方不建议使用这些接口,毕竟会跟Spring进行耦合,并且,现在的Spring版本都可以通过依赖注入的xml配置方式或者注解方式将想注入的对象注入到任何bean中,这种方式就显得比较麻烦了。
代码示例:
package examples;
import lombok.Getter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@Getter
public class ContextContainedBean implements ApplicationContextAware, BeanNameAware {
private ApplicationContext applicationContext;
private String beanName;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void setBeanName(String s) {
this.beanName = s;
}
}
1.6.3. Other Aware Interfaces
除了1.6.2提供的两种Aware接口,Spring还提供了一些其他接口,可以参考官方文档:Other Aware Interfaces