重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
Spring给我们提供了一种当bean销毁时调用某个方法
的方式。那么,Spring底层到底是如何实现的呢?接下来,我们将从源码+案例的方式来解析:spring如何实现当bean销毁时调用某个方法的。
当spring容器关闭
的时候(调用close())方法的时候,所有的单例bean都会被销毁,并且对于实现destroy方法的bean,也会在此刻执行各自自定义的销毁逻辑。
提示:
是spring容器关闭的时候调用bean销毁逻辑,不是垃圾回收、程序意外终止、程序正常终止…的时候。
1、注册DisposableBeans
。在‘初始化后’会对BeanDefinition进行判断,判断该BeanDefinition是否具备destroy方法,如果具备则把BeanDefinition注册到DisposableBeans。具体如何判断的,我们下面会讲;
2、执行destroy方法
。当调用close方法的时候,会遍历DisposableBeans执行每一个销毁方法。
此处不仅仅写了代码示例,也把源码贴出来进行验证。
使用@PreDestroy注解代码示例:
@Component
public class UserService {@Autowired
private OrderService orderService;
public void test(){System.out.println(orderService);
}
@PreDestroy
public void myDestroyUserServiceMethod () {System.out.println("UserService#myDestroyUserServiceMethod");
}
}
源码:
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {// hasDestroyMethod: 实现了DisposableBean或者AutoCloseable接口 ,或者创建bean的时候手动指定了销毁方法( 比如@Bean(destroyMethod = "destory")、xml中的bean标签中指定destroyMethod)
return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
// @PreDestroy注解
(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
bean, getBeanPostProcessorCache().destructionAware))));
}
代码调试:
CommonAnnotationBeanPostProcessor:
UserService#myDestroyUserServiceMethod销毁方法在Spring容器启动
的时候就已经被记录在CommonAnnotationBeanPostProcessor中了,当调用org.springframework.beans.factory.support.AbstractBeanFactory#requiresDestruction判断该bean是否定义销毁逻辑的时候返回的是true:
代码示例:
@Component
public class UserService implements DisposableBean {@Autowired
private OrderService orderService;
public void test(){System.out.println(orderService);
}
@Override
public void destroy () {System.out.println("UserService#destroy");
}
}
源码:
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {// 是否实现了这两个接口中的一个
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) { return true;
}
// 判断BeanDefinition是否指定了销毁方法
return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
}
源码调试:
UserService 实现了 DisposableBean 接口,所以DisposableBeanAdapter.hasDestroyMethod(bean, mbd)返回true,且可以发现CommonAnnotationBeanPostProcessor#lifecycleMetadataCache集合中的UserService.class并没指定destroyMethods:
手动指定dstroy方法有两种方式:
1、@Bean注解方式指定destroyMethod;
2、XML文件中< bean >标签里面指定destry-method;
public class OrderService {public void destroy () {System.out.println("OrderService#destroy");
}
}
@ComponentScan("com.cms")
public class AppConfig {@Bean(destroyMethod = "destroy")
public OrderService createOrderService () {return new OrderService();
}
}
手动指定destroy方法((inferred))代码示例:
public class OrderService {// 必须是close方法
public void close () {System.out.println("OrderService#destroy");
}
}
@ComponentScan("com.cms")
public class AppConfig {@Bean(destroyMethod = "(inferred)")
public OrderService createOrderService () {return new OrderService();
}
}
源码:
@Nullable
private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {// 判断BeanDefinition是否指定了销毁方法(比如创建bean的时候(@Bean、xml),手动指定destroyMethod)
String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
// 下面这种定义销毁的方式,不常用。流程:先定义销毁方法-(inferred) ,然后调用close方法。
if (destroyMethodName == null) { destroyMethodName = beanDefinition.getDestroyMethodName(); //
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
(destroyMethodName == null && bean instanceof AutoCloseable)) { // Only perform destroy method inference or Closeable detection
// in case of the bean not explicitly implementing DisposableBean
destroyMethodName = null;
if (!(bean instanceof DisposableBean)) {try {destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
}
catch (NoSuchMethodException ex) {try { destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
}
catch (NoSuchMethodException ex2) { // no candidate destroy method found
}
}
}
}
beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
}
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}
手动指定destroy方法(MergedBeanDefinitionPostProcessor后置处理器设置销毁方法)@Component
public class MyMergeBdfPostProcesser implements MergedBeanDefinitionPostProcessor {@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class>beanType, String beanName) {if (beanName.equals("myDisposableBean3")){ beanDefinition.setDestroyMethodName("a");
}
}
}
@Component
public class MyDisposableBean3 {public void a() {System.out.println("MyMergeBdfPostProcesser-后置处理器销毁");
}
}
或者
@Component
public class MyMergeBdfPostProcesser2 implements MergedBeanDefinitionPostProcessor {@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class>beanType, String beanName) {if (beanName.equals("myDisposableBean4")){ beanDefinition.setDestroyMethodName("(inferred)");
}
}
}
@Component
public class MyDisposableBean4 {// public void close() {// System.out.println("close销毁");
// }
public void shutdown() {System.out.println("shutdown销毁");
}
}
二、Bean销毁-源码分析
声明关键点1、原型bean即使定义了销毁方法,也不会执行销毁方法
。因为我们的原型bean根本没有存,更不要说去调用原型bean的销毁方法了。
源码位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
// 只做一件事情:注册实现了'销毁'方法的bean。
registerDisposableBeanIfNecessary(beanName, bean, mbd);
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
// if(不是'多例'bean && 有销毁方法)
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) { if (mbd.isSingleton()) { // Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
else { // A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, acc));
}
}
}
销毁源码位置:org.springframework.context.support.AbstractApplicationContext#close
protected void destroyBeans() {// 只对单例bean存储销毁方法,原型bean不会存储(因为原型bean每次调用都会创建新bean对象)
// DefaultListableBeanFactory
getBeanFactory().destroySingletons();
}
在Spring容器关闭过程时:
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧