玖叶教程网

前端编程开发入门

Spring Bean的生命周期:阶段12-Bean销毁阶段

触发bean销毁的几种方式:

  1. 调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyBean
  2. 调用org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons
  3. 调用ApplicationContext中的close方法

Bean销毁阶段会依次执行:

  1. 轮询beanPostProcessors列表,如果是DestructionAwareBeanPostProcessor这种类型的,会调用其内部的postProcessBeforeDestruction方法。
  2. 如果bean实现了org.springframework.beans.factory.DisposableBean接口,会调用这个接口中的destroy方法。
  3. 调用bean自定义的销毁方法。

DestructionAwareBeanPostProcessor接口

看一下源码:

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * bean销毁前调用的方法
     */
    void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

    /**
     * 用来判断bean是否需要触发postProcessBeforeDestruction方法
     */
    default boolean requiresDestruction(Object bean) {
        return true;
    }

}

这个接口有个关键的实现类:

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction方法中会调用bean中所有标注了@PreDestroy的方法。

自定义销毁方法有3种方式:

方式1:xml中指定销毁方法

<bean destroy-method="bean中方法名称"/>

方式2:@Bean中指定销毁方法

@Bean(destroyMethod = "销毁的方法")

方式3:api的方式指定销毁方法

this.beanDefinition.setDestroyMethodName(methodName);

初始化方法最终会赋值给下面这个字段

org.springframework.beans.factory.support.AbstractBeanDefinition#destroyMethodName

下面来看销毁的案例:

public class ServiceA {
    public ServiceA() {
        System.out.println("create " + this.getClass());
    }
}

自定义一个DestructionAwareBeanPostProcessor

public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        System.out.println("准备销毁bean:" + beanName);
    }
}

来个测试类:

      @Test
      public void test1() {
          DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

          //添加自定义的DestructionAwareBeanPostProcessor
          factory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());

          //向容器中注入3个单例bean
          factory.registerBeanDefinition("serviceA1", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());
          factory.registerBeanDefinition("serviceA2", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());
          factory.registerBeanDefinition("serviceA3", BeanDefinitionBuilder.genericBeanDefinition(ServiceA.class).getBeanDefinition());

          //触发所有单例bean初始化
          factory.preInstantiateSingletons(); //@1

          System.out.println("销毁serviceA1");
          //销毁指定的bean
          factory.destroySingleton("serviceA1");//@2

          System.out.println("触发所有单例bean的销毁");
          factory.destroySingletons();
      }

上面使用了2种方式来触发bean的销毁[@1和@2]

运行输出:

create class org.ljgui.spring.demo7.ServiceA
create class org.ljgui.spring.demo7.ServiceA
create class org.ljgui.spring.demo7.ServiceA
销毁serviceA1
准备销毁bean:serviceA1
触发所有单例bean的销毁
准备销毁bean:serviceA3
准备销毁bean:serviceA2

可以看到postProcessBeforeDestruction被调用了3次,依次销毁3个自定义的bean。

案例2:触发@PreDestroy标注的方法被调用。

上面说了这个注解是在CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction中被处理的,所以只需要将这个加入BeanPostProcessor列表就可以了。

再来个类:

public class ServiceB {
    public ServiceB() {
        System.out.println("create " + this.getClass());
    }

    @PreDestroy
    public void preDestroy() { //@1
        System.out.println("preDestroy()");
    }
}

@1:标注了@PreDestroy注解

测试用例:

    public void test2() {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //添加自定义的DestructionAwareBeanPostProcessor
        factory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor()); //@1
        //将CommonAnnotationBeanPostProcessor加入
        factory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor()); //@2

        //向容器中注入bean
        factory.registerBeanDefinition("serviceB", BeanDefinitionBuilder.genericBeanDefinition(ServiceB.class).getBeanDefinition());

        //触发所有单例bean初始化
        factory.preInstantiateSingletons();

        System.out.println("销毁serviceB");
        //销毁指定的bean
        factory.destroySingleton("serviceB");
    }

@1:放入了一个自定义的DestructionAwareBeanPostProcessor

@2:放入了CommonAnnotationBeanPostProcessor,这个会处理bean中标注@PreDestroy注解的方法

看效果运行输出:

create class org.ljgui.spring.demo7.ServiceB
销毁serviceB
准备销毁bean:serviceB
preDestroy()

案例3:看一下销毁阶段的执行顺序

实际上ApplicationContext内部已经将Spring内部一些常见的必须的BeannPostProcessor自动装配到beanPostProcessors列表中,比如熟悉的下面的几个:

1.org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
  用来处理@Resource、@PostConstruct、@PreDestroy的
2.org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
  用来处理@Autowired、@Value注解
3.org.springframework.context.support.ApplicationContextAwareProcessor
  用来回调Bean实现的各种Aware接口

所以通过ApplicationContext来销毁bean,会触发3种方式的执行。

下面就以AnnotationConfigApplicationContext来演示一下销毁操作。

来一个类:

public class ServiceA implements DisposableBean {

    public ServiceA() {
        System.out.println("创建ServiceA实例");
    }

    @PreDestroy
    public void preDestroy1() {
        System.out.println("preDestroy1()");
    }

    @PreDestroy
    public void preDestroy2() {
        System.out.println("preDestroy2()");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean接口中的destroy()");
    }

    //自定义的销毁方法
    public void customDestroyMethod() { //@1
        System.out.println("我是自定义的销毁方法:customDestroyMethod()");
    }
}

上面的类中有2个方法标注了@PreDestroy, 这个类实现了DisposableBean接口,重写了接口的中的destroy方法。

@1:这个destroyMethod一会通过@Bean注解的方式,将其指定为自定义方法。

来看测试用例:

@Configurable
public class DestroyTest {

    @Bean(destroyMethod = "customDestroyMethod") //@1
    public ServiceA serviceA() {
        return new ServiceA();
    }

    @Test
    public void test1() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(DestroyTest.class);
        //启动容器
        System.out.println("准备启动容器");
        context.refresh();
        System.out.println("容器启动完毕");
        System.out.println("serviceA:" + context.getBean(ServiceA.class));
        //关闭容器
        System.out.println("准备关闭容器");
        //调用容器的close方法,会触发bean的销毁操作
        context.close(); //@2
        System.out.println("容器关闭完毕");
    }
}

上面这个类标注了@Configuration,表示是一个配置类,内部有个@Bean标注的方法,表示使用这个方法来定义一个bean。

@1:通过destroyMethod属性将customDestroyMethod指定为自定义销毁方法。

@2:关闭容器,触发bean销毁操作。

来运行test1,输出:

准备启动容器
创建ServiceA实例
容器启动完毕
serviceA:org.ljgui.spring.demo8.ServiceA@6ae4d4
准备关闭容器
preDestroy2()
preDestroy1()
DisposableBean接口中的destroy()
我是自定义的销毁方法:customDestroyMethod()
容器关闭完毕

可以看出销毁方法调用的顺序:

  1. @PreDestroy标注的所有方法
  2. DisposableBean接口中的destroy()
  3. 自定义的销毁方法。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言