前言java
本文轉自「天河聊技術」微信公衆號spring
本次主要介紹bean銷燬的源碼解析緩存
正文微信
找到這個方法併發
org.springframework.context.support.AbstractApplicationContext#refresh的這一行代碼app
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
進入這個方法ide
org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactorypost
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
找到刷新beanFactory的這一行代碼ui
refreshBeanFactory();
進入到這個方法this
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
@Override protected final void refreshBeanFactory() throws BeansException { // 若是存在beanFactory if (hasBeanFactory()) { // 銷燬bean destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
// 若是存在beanFactory if (hasBeanFactory()) { // 銷燬bean destroyBeans(); closeBeanFactory(); }
進入到這個方法org.springframework.context.support.AbstractApplicationContext#destroyBeans
protected void destroyBeans() { // 獲取beanFactory,並銷燬單例的bean getBeanFactory().destroySingletons(); }
進入到這個方法
org.springframework.beans.factory.support.DefaultListableBeanFactory#destroySingletons
@Override public void destroySingletons() { super.destroySingletons(); // 清除記錄的單例beanName的緩存 this.manualSingletonNames.clear(); clearByTypeCache(); }
跟蹤第一行代碼進入到這個方法
@Override public void destroySingletons() { super.destroySingletons(); // 清空beanFactory緩存 this.factoryBeanObjectCache.clear(); }
跟蹤第一行代碼,進入到這個方法
public void destroySingletons() { if (logger.isDebugEnabled()) { logger.debug("Destroying singletons in " + this); } // 這裏使用ConcurrentHashMap本地緩存單例的bean實例,訪問次數比較多,提搞併發量 synchronized (this.singletonObjects) { this.singletonsCurrentlyInDestruction = true; } String[] disposableBeanNames; // 這裏是用LinkedHashMap本地緩存銷燬的bean實例 synchronized (this.disposableBeans) { disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet()); } for (int i = disposableBeanNames.length - 1; i >= 0; i--) { // 銷燬單例的bean destroySingleton(disposableBeanNames[i]); } this.containedBeanMap.clear(); this.dependentBeanMap.clear(); this.dependenciesForBeanMap.clear(); // 同步清空緩存 synchronized (this.singletonObjects) { this.singletonObjects.clear(); this.singletonFactories.clear(); this.earlySingletonObjects.clear(); this.registeredSingletons.clear(); this.singletonsCurrentlyInDestruction = false; } }
找到這行代碼
// 銷燬單例的bean destroySingleton(disposableBeanNames[i]);
public void destroySingleton(String beanName) { // Remove a registered singleton of the given name, if any.刪除單例的bean,從本地緩存中刪除 removeSingleton(beanName); // Destroy the corresponding DisposableBean instance. DisposableBean disposableBean; synchronized (this.disposableBeans) { // 從本地緩存中刪除 disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); } // bean銷燬的邏輯 destroyBean(beanName, disposableBean); }
找到這行代碼
// bean銷燬的邏輯 destroyBean(beanName, disposableBean);
進入到這個方法
protected void destroyBean(String beanName, @Nullable DisposableBean bean) { // Trigger destruction of dependent beans first... 先觸發依賴的bean銷燬,從本地緩存中刪除 Set<String> dependencies = this.dependentBeanMap.remove(beanName); if (dependencies != null) { if (logger.isDebugEnabled()) { logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies); } for (String dependentBeanName : dependencies) { // 這裏用了一個遞歸刪除單例bean,當這個bean沒有依賴的bean要刪除的時候,遞歸結束 destroySingleton(dependentBeanName); } } // Actually destroy the bean now... 這裏開始刪除單例bean if (bean != null) { try { // bean能夠實現DisposableBean這個接口,重寫父類的bean destory的方法 bean.destroy(); } catch (Throwable ex) { logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex); } } // Trigger destruction of contained beans...從本地緩存中銷燬內部bean Set<String> containedBeans = this.containedBeanMap.remove(beanName); if (containedBeans != null) { for (String containedBeanName : containedBeans) { // 這個地方仍是遞歸調用,刪除單例bean,當這個bean沒有內部bean時遞歸結束 destroySingleton(containedBeanName); } } // Remove destroyed bean from other beans' dependencies. 從其餘bean依賴中刪除銷燬的bean synchronized (this.dependentBeanMap) { for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) { Map.Entry<String, Set<String>> entry = it.next(); Set<String> dependenciesToClean = entry.getValue(); dependenciesToClean.remove(beanName); if (dependenciesToClean.isEmpty()) { it.remove(); } } } // Remove destroyed bean's prepared dependency information.刪除銷燬的bean準備的依賴信息 this.dependenciesForBeanMap.remove(beanName); }
找到這行代碼
// bean能夠實現DisposableBean這個接口,重寫父類的bean destory的方法 bean.destroy();
進而跟蹤到這個方法
public interface DisposableBean { /** * Invoked by a BeanFactory on destruction of a singleton. * @throws Exception in case of shutdown errors. * Exceptions will get logged but not rethrown to allow * other beans to release their resources too. */ // 被BeanFactory調用,用於銷燬單例對象。 void destroy() throws Exception; }
找到這個方法的一個適配器實現
org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
@Override public void destroy() { // 執行beanPostProcessors,beanPostProcessors用對對bean的過程進行處理的抽象 if (!CollectionUtils.isEmpty(this.beanPostProcessors)) { for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) { // 在bean銷燬以前進行一些處理 processor.postProcessBeforeDestruction(this.bean, this.beanName); } } if (this.invokeDisposableBean) { if (logger.isDebugEnabled()) { logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'"); } try { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((DisposableBean) bean).destroy(); return null; }, acc); } else { // bean實現DisposableBean接口的方式,註解調用子類destroy方法 ((DisposableBean) bean).destroy(); } } catch (Throwable ex) { String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'"; if (logger.isDebugEnabled()) { logger.warn(msg, ex); } else { logger.warn(msg + ": " + ex); } } } if (this.destroyMethod != null) { // 執行bean定義中指定的bean銷燬方法 invokeCustomDestroyMethod(this.destroyMethod); } else if (this.destroyMethodName != null) { Method methodToCall = determineDestroyMethod(this.destroyMethodName); if (methodToCall != null) { invokeCustomDestroyMethod(methodToCall); } } }
找到這行代碼
// 在bean銷燬以前進行一些處理 processor.postProcessBeforeDestruction(this.bean, this.beanName);
@Override public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { // 找到bean建立和銷燬的metadata信息 LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { // 執行bean的銷燬方法 metadata.invokeDestroyMethods(bean, beanName); } catch (InvocationTargetException ex) { String msg = "Invocation of destroy method failed on bean with name '" + beanName + "'"; if (logger.isDebugEnabled()) { logger.warn(msg, ex.getTargetException()); } else { logger.warn(msg + ": " + ex.getTargetException()); } } catch (Throwable ex) { logger.error("Failed to invoke destroy method on bean with name '" + beanName + "'", ex); } }
// 找到bean建立和銷燬的metadata信息 LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) { if (this.lifecycleMetadataCache == null) { // Happens after deserialization, during destruction... return buildLifecycleMetadata(clazz); } // Quick check on the concurrent map first, with minimal locking. LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz); if (metadata == null) { synchronized (this.lifecycleMetadataCache) { metadata = this.lifecycleMetadataCache.get(clazz); if (metadata == null) { metadata = buildLifecycleMetadata(clazz); this.lifecycleMetadataCache.put(clazz, metadata); } return metadata; } } return metadata; }
進入這一行代碼
return buildLifecycleMetadata(clazz);
// 構建bean建立和銷燬metadata對象 private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) { final boolean debug = logger.isDebugEnabled(); LinkedList<LifecycleElement> initMethods = new LinkedList<>(); LinkedList<LifecycleElement> destroyMethods = new LinkedList<>(); Class<?> targetClass = clazz; do { final LinkedList<LifecycleElement> currInitMethods = new LinkedList<>(); final LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<>(); ReflectionUtils.doWithLocalMethods(targetClass, method -> { // 判斷方法上是否有@PostConstruct這個註解 if (initAnnotationType != null && method.isAnnotationPresent(initAnnotationType)) { LifecycleElement element = new LifecycleElement(method); currInitMethods.add(element); if (debug) { logger.debug("Found init method on class [" + clazz.getName() + "]: " + method); } } // @PreDestroy 判斷方法上是否有這個註解 if (destroyAnnotationType != null && method.isAnnotationPresent(destroyAnnotationType)) { currDestroyMethods.add(new LifecycleElement(method)); if (debug) { logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method); } } }); initMethods.addAll(0, currInitMethods); destroyMethods.addAll(currDestroyMethods); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return new LifecycleMetadata(clazz, initMethods, destroyMethods); }
從這個方法能夠看出,bean的方法上加這個註解@PreDestroy就是bean銷燬的時候要執行的方法。
返回這個方法org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeDestruction的這一行代碼
try { // 執行bean的銷燬方法 metadata.invokeDestroyMethods(bean, beanName); }
執行bean的銷燬方法。
若是bean實現了DisposableBean接口的destory方法,就會執行這個方法來執行銷燬bean邏輯,下面是源碼實現
// 若是bean實現了DisposableBean接口 if (this.invokeDisposableBean) { if (logger.isDebugEnabled()) { logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'"); } try { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((DisposableBean) bean).destroy(); return null; }, acc); } else { // bean實現DisposableBean接口的方式,註解調用子類destroy方法 ((DisposableBean) bean).destroy(); } } catch (Throwable ex) { String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'"; if (logger.isDebugEnabled()) { logger.warn(msg, ex); } else { logger.warn(msg + ": " + ex); } } }
還有一種狀況
if (this.destroyMethod != null) { // 執行bean定義中指定的bean銷燬方法 invokeCustomDestroyMethod(this.destroyMethod); } else if (this.destroyMethodName != null) { Method methodToCall = determineDestroyMethod(this.destroyMethodName); if (methodToCall != null) { invokeCustomDestroyMethod(methodToCall); } } }
跟蹤下destroyMethod這個變量是在哪裏賦值的
返回找到這個類的構造器
org.springframework.beans.factory.support.DisposableBeanAdapter#DisposableBeanAdapter(java.lang.Object, java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.util.List<org.springframework.beans.factory.config.BeanPostProcessor>, java.security.AccessControlContext)的這幾行代碼
// 從bean定義中獲取指定的銷燬方法 destory-method標籤屬性 String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition); if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) && !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { this.destroyMethodName = destroyMethodName; this.destroyMethod = determineDestroyMethod(destroyMethodName);
跟蹤進入這行代碼
String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
@Nullable private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) { // 從bean定義中獲取bean的銷燬方法 String 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 if (!(bean instanceof DisposableBean)) { try { return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName(); } catch (NoSuchMethodException ex) { try { return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName(); } catch (NoSuchMethodException ex2) { // no candidate destroy method found } } } return null; } return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null); }
bean定義中的具體源碼解析後續在詳細介紹。
總結一下
若是要在一個bean銷燬的時候執行一些定製化的邏輯,有三種方式
一、在bean定義中bean標籤中destory-method指定
二、實現DisposableBean將誒口,重寫destory方法
三、在bean的方法上加上@PreDestroy註解
bean的初始化相似,後續解析。
最後
本次介紹到這裏,以上內容僅供參考。