这是我参与2022首次更文挑战的第40天,活动详情查看2022首次更文挑战
销毁bean解析的顺序
在同一bean实例上使用所有机制来进行bean销毁,这种情况下,Spring首先调用拥@PreDestroy注解的方法,然后调用DisposableBean.destroy(),最后调用XML定义配置的destroy()方法。
使用关闭钩子
在Spring中销毁回调函数的唯一缺点是它们不会自动触发,需要记住在应用关闭之前调用AbstractApplicationContext.destroy()。当应用作为servlet运行时,可简单地在servlet的destroy()方法中调用destroy()。Java允许创建一个关闭钩子,它在应用关闭之前执行的一个线程,这是调用AbstractApplicationContext的destroy()方法的一种理想方法。利用此机制的最简单方法是使用AbstractApplicationContext的registryShutdownHook()方法。该方法自动指示Spring注册底层JVM运行时的关闭钩子。在运行方法中添加ctx.registerShutdownHook的调用,同时删除对ctx.destroy()或close()的调用。
public static void main(String... args){
GenericApplicationContext ctx=new AnnotationConfigApplicationContext(DestructiveBeanConfig.class);
ctx.getBean(DestructiveBean.class);
System.out.println("调用bean销毁方法开始");
ctx.registerShutdownHook();
System.out.println("调用bean销毁方法结束");
}
Spring感知bean
使用BeanNameAware接口
获取自己名称的bean可实现BeanNameAware接口,它有一个方法setBeanName(String)。在完成bean的配置后且在调用任何声明周期之前,Spring会调用setBeanName()方法,setBeanName的实现仅仅将容器传入的值存储在字段中供使用。
bean使用BeanNameAware获取自己的名称
public class NameSinger implements BeanNameAware{
private String name;
public void setBeanName(Stirng beanName){
this.name=beanName;
}
public void sing(){
System.out.println("Singer"+name+"use sing()");
}
}
从ApplicationContext中检索Singer实例,然后调用sing()方法。
public class NamedSingerDemo{
public static void main(String... args){
GenericXmlApplication ctx = new GenericXmlApplication();
ctx.load("classpath:spring/app-context.xml");
ctx.refresh();
NameSinger bean=(NameSinger)ctx.getBean("eleven");
bean.sing();
ctx.close();
}
}
bean在内部需要某种名称,让它们实现一个带有setName()方法的接口,该接口是特定于应用,通过依赖注入为每个bean命名,通过这种方式,既可以保留用于配置的名称,又无须完成不必要的配置以为bean名称赋予业务含义。
使用ApplicationContextAware接口
通过使用ApplicationContextAware接口,bean可以获得对配置它们的ApplicationContext实例的引用,创建此接口的主要原因,是为了允许bean在应用访问Spring的ApplicationContext.ApplicationContext并不仅仅用于查找bean,它可以执行许多其他任务,如销毁所有单例,但在销毁之前会依次通知每个单例。
使用一个ApplicationContextAware接口创建一个bean,自动创建和配置关闭钩子bean如下:
public class ShutdownHookBean implements ApplicationContextAware{
private ApplicationContext ctx;
public void setApplicationContext(ApplicationContext ctx) throws BeansException{
if(ctx instanceof GenericApplicationContext){
((GenericApplicationContext)ctx).registerShutdownHook();
}
}
}
ApplicationContextAware接口定义了一个方法setApplicationContext(ApplicationContext),Spring调用它,从而将ApplicationContext的引用传递给bean,ShutdownHookBean类检查ApplicationContext是否属于GenericApplicationContext类型,这代表它支持registerShutdownHook()方法,如果是,则会向ApplicationContext注册一个关闭钩子。