深入Spring专题(33)

109 阅读2分钟

这是我参与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注册一个关闭钩子。