真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

【Spring源碼系列】Bean生命周期-Bean銷毀-創(chuàng)新互聯(lián)

文章目錄
  • 前言
  • 一、Bean銷毀介紹
    • bean銷毀的時機
    • spring注冊DestroyBean時機
    • 定義bean銷毀方式以及源碼調(diào)試
      • 使用@PreDestroy注解
      • 實現(xiàn)DisposableBean或者AutoCloseable接口
      • 手動指定destroy方法(@Bean、XML)
      • 手動指定destroy方法((inferred))
      • 手動指定destroy方法(MergedBeanDefinitionPostProcessor后置處理器設(shè)置銷毀方法)
  • 二、Bean銷毀-源碼分析
    • 聲明關(guān)鍵點
    • 源代碼
      • 注冊
      • 銷毀

創(chuàng)新互聯(lián)公司成立于2013年,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目網(wǎng)站制作、成都做網(wǎng)站網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元甘泉做網(wǎng)站,已為上家服務(wù),為甘泉各地企業(yè)和個人服務(wù),聯(lián)系電話:18980820575前言

Spring給我們提供了一種當(dāng)bean銷毀時調(diào)用某個方法的方式。那么,Spring底層到底是如何實現(xiàn)的呢?接下來,我們將從源碼+案例的方式來解析:spring如何實現(xiàn)當(dāng)bean銷毀時調(diào)用某個方法的。

一、Bean銷毀介紹 bean銷毀的時機

當(dāng)spring容器關(guān)閉的時候(調(diào)用close())方法的時候,所有的單例bean都會被銷毀,并且對于實現(xiàn)destroy方法的bean,也會在此刻執(zhí)行各自自定義的銷毀邏輯。

提示:
是spring容器關(guān)閉的時候調(diào)用bean銷毀邏輯,不是垃圾回收、程序意外終止、程序正常終止…的時候。

spring注冊DestroyBean時機

1、注冊DisposableBeans。在‘初始化后’會對BeanDefinition進行判斷,判斷該BeanDefinition是否具備destroy方法,如果具備則把BeanDefinition注冊到DisposableBeans。具體如何判斷的,我們下面會講;
在這里插入圖片描述
2、執(zhí)行destroy方法。當(dāng)調(diào)用close方法的時候,會遍歷DisposableBeans執(zhí)行每一個銷毀方法。

定義bean銷毀方式以及源碼調(diào)試

此處不僅僅寫了代碼示例,也把源碼貼出來進行驗證。

使用@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: 實現(xiàn)了DisposableBean或者AutoCloseable接口	,或者創(chuàng)建bean的時候手動指定了銷毀方法( 比如@Bean(destroyMethod = "destory")、xml中的bean標(biāo)簽中指定destroyMethod)
		return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
				// @PreDestroy注解
				(hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors(
						bean, getBeanPostProcessorCache().destructionAware))));
	}

代碼調(diào)試:
?CommonAnnotationBeanPostProcessor:
在這里插入圖片描述UserService#myDestroyUserServiceMethod銷毀方法在Spring容器啟動的時候就已經(jīng)被記錄在?CommonAnnotationBeanPostProcessor中了,當(dāng)調(diào)用org.springframework.beans.factory.support.AbstractBeanFactory#requiresDestruction判斷該bean是否定義銷毀邏輯的時候返回的是true:
在這里插入圖片描述

實現(xiàn)DisposableBean或者AutoCloseable接口

代碼示例:

@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) {// 是否實現(xiàn)了這兩個接口中的一個
		if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {	return true;
		}
		// 判斷BeanDefinition是否指定了銷毀方法
		return inferDestroyMethodIfNecessary(bean, beanDefinition) != null;
	}

源碼調(diào)試:
UserService 實現(xiàn)了 DisposableBean 接口,所以DisposableBeanAdapter.hasDestroyMethod(bean, mbd)返回true,且可以發(fā)現(xiàn)?CommonAnnotationBeanPostProcessor#lifecycleMetadataCache集合中的UserService.class并沒指定destroyMethods:
在這里插入圖片描述

手動指定destroy方法(@Bean、XML)

手動指定dstroy方法有兩種方式:
1、@Bean注解方式指定destroyMethod;
2、XML文件中< bean >標(biāo)簽里面指定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是否指定了銷毀方法(比如創(chuàng)建bean的時候(@Bean、xml),手動指定destroyMethod)
		String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
		// 下面這種定義銷毀的方式,不常用。流程:先定義銷毀方法-(inferred) ,然后調(diào)用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后置處理器設(shè)置銷毀方法)
@Component
public class MyMergeBdfPostProcesser implements MergedBeanDefinitionPostProcessor {@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, ClassbeanType, 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, ClassbeanType, 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銷毀-源碼分析 聲明關(guān)鍵點

1、原型bean即使定義了銷毀方法,也不會執(zhí)行銷毀方法。因為我們的原型bean根本沒有存,更不要說去調(diào)用原型bean的銷毀方法了。

源代碼 注冊

源碼位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

// 只做一件事情:注冊實現(xiàn)了'銷毀'方法的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每次調(diào)用都會創(chuàng)建新bean對象)
		// DefaultListableBeanFactory
		getBeanFactory().destroySingletons();
	}

在Spring容器關(guān)閉過程時:

  1. 首先發(fā)布ContextClosedEvent事件
  2. 調(diào)用lifecycleProcessor的onCloese()方法
  3. 銷毀單例Bean
    a. 遍歷disposableBeans
    ⅰ. 把每個disposableBean從單例池中移除
    ⅱ. 調(diào)用disposableBean的destroy()
    ⅲ. 如果這個disposableBean還被其他Bean依賴了,那么也得銷毀其他Bean
    ⅳ. 如果這個disposableBean還包含了inner beans,將這些Bean從單例池中移除掉 (inner bean參考https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-inner-beans)
    b. 清空manualSingletonNames,是一個Set,存的是用戶手動注冊的單例Bean的beanName
    c. 清空allBeanNamesByType,是一個Map,key是bean類型,value是該類型所有的beanName數(shù)組
    d. 清空singletonBeanNamesByType,和allBeanNamesByType類似,只不過只存了單例Bean
    這里涉及到一個設(shè)計模式:適配器模式
    在銷毀時,Spring會找出實現(xiàn)了DisposableBean接口的Bean。
    但是我們在定義一個Bean時,如果這個Bean實現(xiàn)了DisposableBean接口,或者實現(xiàn)了AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么這個Bean都屬于“DisposableBean”,這些Bean在容器關(guān)閉時都要調(diào)用相應(yīng)的銷毀方法。
    所以,這里就需要進行適配,將實現(xiàn)了DisposableBean接口、或者AutoCloseable接口等適配成實現(xiàn)了DisposableBean接口,所以就用到了DisposableBeanAdapter。
    會把實現(xiàn)了AutoCloseable接口的類封裝成DisposableBeanAdapter,而DisposableBeanAdapter實現(xiàn)了DisposableBean接口。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧


網(wǎng)站標(biāo)題:【Spring源碼系列】Bean生命周期-Bean銷毀-創(chuàng)新互聯(lián)
標(biāo)題網(wǎng)址:http://weahome.cn/article/hcoji.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部