Spring可二次開發常用接口、類及其源碼詳解


  Spring為了用戶的開發方便和特性支持,開放了一些特殊接口和類,用戶可進行實現或者繼承,常見的如這些: ApplicationContextAware接口、ApplicationEvent抽象類、ApplicationListener接口、BeanNameAware接口、BeanFactoryAware接口、InitializingBean接口、DisposableBean接口、BeanPostProcessor接口。 

一、ApplicationContextAware接口

  AbstractApplicationContext類是Spring容器應用上下文的一個抽象父類,ApplicationContextAware是用來獲取spring的上下文。當一個類需要獲取ApplicationContext實例時,可以通過工具類直接實現ApplicationContextAware接口,返回ApplicationContext對象。如下代碼所示:

   @Component
    public class BeansUtils implements ApplicationContextAware {

        private static ApplicationContext context;

        public static <T> T getBean(Class<T> bean) {
            return context.getBean(bean);
        }
        public static <T> T getBean(String var1, @Nullable Class<T> var2){
            return context.getBean(var1, var2);
        }

        public static ApplicationContext getContext() {
            return context;
        }

        @Override
        public void setApplicationContext(ApplicationContext context) throws BeansException {
            BeansUtils.context = context;
        }
    }

  以上一段代碼就可使獲取ApplicationContext以及某些Bean,那么其原理是什么呢?

  我們在初始化的時候,從入口類ClassPathXmlApplicationContext->AbstractApplicationContext類的的refresh方法 ->prepareBeanFactory方法:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 設置 BeanFactory 的類加載器,我們知道 BeanFactory 需要加載類,也就需要類加載器,這里設置為當前 ApplicationContext 的類加載器
        beanFactory.setBeanClassLoader(getClassLoader());
         // 設置 BeanExpressionResolver
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加一個 BeanPostProcessor,這個 processor 比較簡單,實現了 Aware 接口的幾個特殊的 beans 在初始化的時候,這個 processor 負責回調
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
         // 下面幾行的意思就是,如果某個 bean 依賴於以下幾個接口的實現類,在自動裝配的時候忽略它們,Spring 會通過其他方式來處理這些依賴。
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }// 如果沒有定義 "environment" 這個 bean,那么 Spring 會 "手動" 注冊一個
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
         // 如果沒有定義 "systemProperties" 這個 bean,那么 Spring 會 "手動" 注冊一個
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
         // 如果沒有定義 "systemEnvironment" 這個 bean,那么 Spring 會 "手動" 注冊一個
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }

  beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); spring源碼里面將ApplicationContextAwareProcessor加入到BeanPostProcessor處理器里面了,並且傳的是一個ApplicationContext類型參數進去。

class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ConfigurableApplicationContext applicationContext;
//beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));調用此構造方法把ApplicationContext傳過來 public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) { this.applicationContext = applicationContext; } //實例化之前進行的處理 public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null; if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { //給Aware的實現類set值進去 invokeAwareInterfaces(bean); return null; } }, acc); } else { //給Aware的實現類set值進去 invokeAwareInterfaces(bean); } return bean; } private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver( new EmbeddedValueResolver(this.applicationContext.getBeanFactory())); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } //判讀是否是屬於ApplicationContextAware接口的類 if (bean instanceof ApplicationContextAware) { //調用實現類的setApplicationContext方法把applicationContext set進去 ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }   // ... ... }

  BeanPostProcessor處理器,可以在bean初始化前、后根據自己業務做一些事情。postProcessBeforeInitialization方法里面,里面invokeAwareInterfaces方法是怎樣都會走的,里面有這樣一段代碼((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);這就是去調用具體實現類的setApplicationContext方法把applicationContext傳進去了。其他Aware基本上也是這個道理。

  可以很清楚的了解到ApplicationContextAware實現類在應用啟動的時候就會初始化。

二、ApplicationEvent抽象類、ApplicationListener接口

  1、使用測試

  ApplicationEvent抽象類、ApplicationListener接口是常常搭配使用的:

  • ApplicationEvent:是個抽象類,里面只有一個構造函數和一個長整型的timestamp。
  • ApplicationListener:是一個接口,里面只有一個onApplicationEvent方法。所以自己的類在實現該接口的時候,要實裝該方法。
  • ApplicationContext:如果在上下文中部署一個實現了ApplicationListener接口的bean,那么每當在一個ApplicationEvent發布到 ApplicationContext時,這個bean得到通知。

  因此ApplicationEvent、ApplicationListener、ApplicationContext三者其實這就是標准的Oberver設計模式。如下面一個例子:

public class EmailEvent extends ApplicationEvent {

    private static final long serialVersionUID = 1L;
    public String address;  
    public String text;
    
    public EmailEvent(Object source) {
        super(source);
    }
    
    public EmailEvent(Object source, String address, String text) {
        super(source);
        this.address = address;
        this.text = text;
    }
    
    public void print(){
        System.out.println("hello spring event!");
    }
}

public class EmailListener implements ApplicationListener {

    public void onApplicationEvent(ApplicationEvent  event) {
        if(event instanceof EmailEvent){
            EmailEvent emailEvent = (EmailEvent)event;
            emailEvent.print();
            System.out.println("the source is:"+emailEvent.getSource());
            System.out.println("the address is:"+emailEvent.address);
            System.out.println("the email's context is:"+emailEvent.text);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        EmailEvent event = new EmailEvent("hello","boylmx@163.com","this is a email text!");
        context.publishEvent(event);
    }
}

  測試結果如下:

hello spring event!  
the source is:hello  
the address is:boylmx@163.com  
the email's context is:this is a email text! 

  這就是一個基於ApplicationEvent、ApplicationListener使用的例子,實現Spring事件機制主要有4個類:

  • ApplicationEvent:事件,每個實現類表示一類事件,可攜帶數據。
  • ApplicationListener:事件監聽器,用於接收事件處理時間。
  • ApplicationEventMulticaster:事件管理者,用於事件監聽器的注冊和事件的廣播。
  • ApplicationEventPublisher:事件發布者,委托ApplicationEventMulticaster完成事件發布。

  那我們來進行源碼解析。

  2、ApplicationEvent

  ApplicationEvent表示事件,每個實現類表示一類事件,可攜帶數據。下面以一些Spring提供的標准事件,都繼承了ApplicationEvent。

事件 描述
ContextRefreshedEvent 事件發布在ApplicationContext初始化或刷新時(例如,通過在ConfigurableApplicationContext接口使用refresh()方法)。這里,“初始化”意味着所有bean加載,post-processor bean被檢測到並且激活,單例預先實例化,ApplicationContext對象可以使用了。只要上下文沒有關閉,可以觸發多次刷新,ApplicationContext提供了一種可選擇的支持這種“熱”刷新。例如XmlWebApplicationContext支持熱刷新,但GenericApplicationContext並非如此。具體是在AbstractApplicationContext的finishRefresh()方法中。
ContextRefreshedEvent

事件發布在ApplicationContext初始化或刷新時(例如,通過在ConfigurableApplicationContext接口使用refresh()方法)。這里,“初始化”意味着所有bean加載,post-processor bean被檢測到並且激活,單例預先實例化,ApplicationContext對象可以使用了。只要上下文沒有關閉,可以觸發多次刷新,ApplicationContext提供了一種可選擇的支持這種“熱”刷新。例如,XmlWebApplicationContext支持熱刷新,但GenericApplicationContext並非如此。具體是在AbstractApplicationContext的finishRefresh()方法中。

ContextStartedEvent 事件發布在ApplicationContext開始使用ConfigurableApplicationContext接口start()方法。這里,“開始”意味着所有生命周期bean接收到一個明確的起始信號。通常,這個信號用於明確停止后重新啟動,但它也可以用於啟動組件沒有被配置為自動運行(例如,組件還沒有開始初始化)。
ContextStoppedEvent 事件發布在ApplicationContext停止時通過使用ConfigurableApplicationContext接口上的stop()方法。在這里,“停止”意味着所有生命周期bean接收一個顯式的停止信號。停止上下文可以通過重新調用start()方法。
ContextClosedEvent 事件發布在ApplicationContext關閉時通過關閉ConfigurableApplicationContext接口方法。這里,“封閉”意味着所有單例bean被摧毀。一個封閉的環境達到生命的終結。它不能刷新或重啟。
RequestHandledEvent 一個特定的web事件告訴所有能處理HTTP請求的bean 。這個事件是在請求完成后發布的。這個事件只適用於使用Spring的DispatcherServlet的web應用程序。

  ApplicationEvent代碼如下:

public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;
    private final long timestamp = System.currentTimeMillis();

    public ApplicationEvent(Object source) {
        super(source);
    }

    public final long getTimestamp() {
        return this.timestamp;
    }
}

  3、ApplicationListener

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
   void onApplicationEvent(E event);
}

  當事件監聽器接收到它可以處理的事件,會調用onApplicationEvent()方法。注意到ApplicationListener是泛型參數,這樣可以實現所有繼承了ApplicationEvent的監聽。我們可以盡可能多的注冊想要的事件偵聽器,但是默認情況下事件監聽器同步接收事件。這意味着publishEvent()方法會阻塞直到所有的事件監聽器成處理完事件。這種單線程同步方法的一個特點是,當一個監聽器接收到一個事件時,它運行在事務上下文的發布者線程上(如果事務上下文可用)。如果事件的發布需要另一種策略(譬如多線程)需要實現自己的 ApplicationEventMulticaster接口類。

  4、ApplicationEventMulticaster

  ApplicationEventMulticaster接口方法分為三類,注冊事件監聽器、移除事件監聽器、發布事件。

public interface ApplicationEventMulticaster {
   void addApplicationListener(ApplicationListener<?> listener);
   void addApplicationListenerBean(String listenerBeanName);
   void removeApplicationListener(ApplicationListener<?> listener);
   void removeApplicationListenerBean(String listenerBeanName);
   void removeAllListeners();
   void multicastEvent(ApplicationEvent event);
   void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}

  執行AbstractApplicationContext.initApplicationEventMulticaster() 方法時會實例化一個bean name為applicationEventMulticaster的SimpleApplicationEventMulticaster,它的父類實現了前5個方法依靠一個內部類ListenerRetriever維護了一個Set<ApplicationListener<?>>,本質事件監聽器的注冊或移除就是對這個Set的添加和移除操作。

public abstract class AbstractApplicationEventMulticaster
      implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
   private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
   
   @Override
   public void addApplicationListener(ApplicationListener<?> listener) {
      synchronized (this.retrievalMutex) {
         // 如果已經注冊,則顯式刪除代理的目標,以避免對同一個偵聽器進行雙重調用。
         Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
         if (singletonTarget instanceof ApplicationListener) {
            this.defaultRetriever.applicationListeners.remove(singletonTarget);
         }
         this.defaultRetriever.applicationListeners.add(listener);
         this.retrieverCache.clear();
      }
   }
 
   @Override
   public void removeApplicationListener(ApplicationListener<?> listener) {
      synchronized (this.retrievalMutex) {
         this.defaultRetriever.applicationListeners.remove(listener);
         this.retrieverCache.clear();
      }
   }
 
   private class ListenerRetriever {
      public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
      public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
      private final boolean preFiltered;
      public ListenerRetriever(boolean preFiltered) {
         this.preFiltered = preFiltered;
      }
      public Collection<ApplicationListener<?>> getApplicationListeners() {
         List<ApplicationListener<?>> allListeners = new ArrayList<>(
               this.applicationListeners.size() + this.applicationListenerBeans.size());
         allListeners.addAll(this.applicationListeners);
         if (!this.applicationListenerBeans.isEmpty()) {
            BeanFactory beanFactory = getBeanFactory();
            for (String listenerBeanName : this.applicationListenerBeans) {
               try {
                  ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                  if (this.preFiltered || !allListeners.contains(listener)) {
                     allListeners.add(listener);
                  }
               }
               catch (NoSuchBeanDefinitionException ex) {
                  // Singleton listener instance (without backing bean definition) disappeared -
                  // probably in the middle of the destruction phase
               }
            }
         }
         if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
            AnnotationAwareOrderComparator.sort(allListeners);
         }
         return allListeners;
      }
   }
}

  接口后兩個方法由子類實現,可以看到SimpleApplicationEventMulticaster擁有一個Executor和ErrorHandler,分表表示監聽器的調用線程池(如果不想使用單線程同步處理則可以設置一個線程池)和監聽器處理事件失敗的處理者(如果設置了的話)否則拋異常。 

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
   @Nullable
   private Executor taskExecutor;
   @Nullable
   private ErrorHandler errorHandler;
   public SimpleApplicationEventMulticaster() {
   }
   public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
      setBeanFactory(beanFactory);
   }
   public void setTaskExecutor(@Nullable Executor taskExecutor) {
      this.taskExecutor = taskExecutor;
   }
   public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
      this.errorHandler = errorHandler;
   }
   @Override
   public void multicastEvent(ApplicationEvent event) {
      //廣播事件,可以自動分析出ApplicationEvent是那種事件類型
 multicastEvent(event, resolveDefaultEventType(event));
   }
   @Override
   public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
      ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
      //調用父類方法getApplicationListeners只取得能處理此類事件的時間監聽器,依次處理
      for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
         Executor executor = getTaskExecutor();
         if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
         }
         else {
            invokeListener(listener, event);
         }
      }
   }
 
   private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
      return ResolvableType.forInstance(event);
   }
 
   protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
      ErrorHandler errorHandler = getErrorHandler();
      if (errorHandler != null) {
         try {
            doInvokeListener(listener, event);
         }
         catch (Throwable err) {
            errorHandler.handleError(err);
         }
      }
      else {
         doInvokeListener(listener, event);
      }
   }
 
   @SuppressWarnings({"unchecked", "rawtypes"})
   private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
      try {
         listener.onApplicationEvent(event);
      }
      catch (ClassCastException ex) {  // 省略}
   }
 
   private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {// 省略}
}

  5、ApplicationEventPublisher

@FunctionalInterface
public interface ApplicationEventPublisher {
   default void publishEvent(ApplicationEvent event) {
      publishEvent((Object) event);
   }
   void publishEvent(Object event);
}

  ApplicationEventPublisher很簡單只有兩個發布事件的方法,AbstractApplicationContext是它的默認實現類,下面是具體實現。

@Override
public void publishEvent(ApplicationEvent event) {
   publishEvent(event, null);
}
@Override
public void publishEvent(Object event) {
   publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
   Assert.notNull(event, "Event must not be null");
 
   ApplicationEvent applicationEvent;
   if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent) event;
   }
   else {
      applicationEvent = new PayloadApplicationEvent<>(this, event);
      if (eventType == null) {
         eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
      }
   }
 
   // Multicast right now if possible - or lazily once the multicaster is initialized
   if (this.earlyApplicationEvents != null) {
      this.earlyApplicationEvents.add(applicationEvent);
   }
   else {
      getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
   }
 
   // Publish event via parent context as well...
   if (this.parent != null) {
      if (this.parent instanceof AbstractApplicationContext) {
         ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
      }
      else {
         this.parent.publishEvent(event);
      }
   }
}

  可以看到事件的發布依賴於前面提到的bean name是applicationEventMulticaster的SimpleApplicationEventMulticaster。關於監聽器注冊有兩種方法:接口實現、注解,代碼如下:

//  使用接口實現方式
public class RegisterListener implements ApplicationListener<UserRegisterEvent> {
    @Override
    public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {//../省略邏輯
    }
}

//  使用@EventListener注解方式
@Component
public class AnnotationRegisterListener { @EventListener public void register(UserRegisterEvent userRegisterEvent)
    {
    //../省略邏輯
    }
}

三、InitializingBean接口

  當需要在bean的全部屬性設置成功后做些特殊的處理,可以讓該bean實現InitializingBean接口。效果等同於bean的init-method屬性的使用或者@PostContsuct注解的使用,它只包括afterPropertiesSet方法,凡是繼承該接口的類,在初始化bean的時候都會執行該方法。

  測試代碼如下:

public class TestInitializingBean implements InitializingBean{
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("ceshi InitializingBean");        
    }
    public void testInit(){
        System.out.println("ceshi init-method");        
    }
}

  配置文件如下:

<bean id="testInitializingBean" class="com.TestInitializingBean" ></bean>

  Main函數如下:

public class Main {
    public static void main(String[] args){
        ApplicationContext context = new FileSystemXmlApplicationContext("/src/main/java/com/beans.xml");
    }
}

  測試結果為:

ceshi InitializingBean

  這說明在spring初始化bean的時候,如果bean實現了InitializingBean接口,會自動調用afterPropertiesSet方法。那么在配置bean的時候使用init-method配置也可以為bean配置初始化方法,那這兩個哪個會先執行呢,接下來測試一下,修改配置文件,加上init-method:

<bean id="testInitializingBean" class="com.TestInitializingBean" init-method="testInit"></bean>

  運行程序,得出結果:

ceshi InitializingBean
ceshi init-method

  從結果可以看出,在Spring初始化bean的時候,如果該bean實現了InitializingBean接口,並且同時在配置文件中指定了init-method,系統則是先調用afterPropertieSet()方法,然后再調用init-method中指定的方法。

  那么這種方式在spring中是怎么實現的呢,通過查看Spring加載bean的源碼類AbstractAutowiredCapableBeanFactory可以看出其中的奧妙,AbstractAutowiredCapableBeanFactory類中的invokeInitMethods說的非常清楚,如下:

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
    //判斷該bean是否實現了實現了InitializingBean接口,如果實現了InitializingBean接口,則只掉調用bean的afterPropertiesSet方法
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
         
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        //直接調用afterPropertiesSet
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                },getAccessControlContext());
            } catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }                
        else {
            //直接調用afterPropertiesSet
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }
    if (mbd != null) {
        String initMethodName = mbd.getInitMethodName();
        //判斷是否指定了init-method方法,如果指定了init-method方法,則再調用制定的init-method
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            //進一步查看該方法的源碼,可以發現init-method方法中指定的方法是通過反射實現
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

  總結:

  • 注解、InitializingBean、init-method三種方式的執行順序是:先注解,然后執行InitializingBean接口中定義的方法,最后執行init-method屬性指定的方法。
  • Spring為bean提供了兩種初始化bean的方式,實現InitializingBean接口,實現afterPropertiesSet方法,或者在配置文件中通過init-method指定,兩種方式可以同時使用。
  • 實現InitializingBean接口是直接調用afterPropertiesSet方法,比通過反射調用init-method指定的方法效率要高一點,但是init-method方式消除了對spring的依賴。
  • 如果調用afterPropertiesSet方法時出錯,則不調用init-method指定的方法。

四、DisposableBean接口

  同InitializingBean原理類似,當需要在bean銷毀之前做些特殊的處理,可以讓該bean實現DisposableBean接口,該接口也只定義了一個destory方法。效果等同於bean的destroy-method屬性的使用或者@PreDestory注解的使用。

  注解、DisposableBean、destroy-method三種方式的執行順序:先注解,然后執行DisposableBean接口中定義的方法,最后執行destroy-method屬性指定的方法。

五、BeanNameAware接口、BeanFactoryAware接口

  Bean都是“無知覺”的,就像黑客帝國中機械工廠里面“養殖”的人類,他們雖然能完成一定的功能,但是根本不知道自己在工廠(BeanFactory)中的代號(id),或者自己是在哪個工廠(BeanFactory的引用)中沉睡。

  BeanNameAware就是讓Bean對Spring有知覺:

public interface BeanNameAware extends Aware {
    void setBeanName(String var1);
}

  BeanFactoryAware讓Bean對工廠有知覺:

public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory var1) throws BeansException;
}

  代碼如下:

public class BeanTest implements BeanNameAware,BeanFactoryAware {

    private String beanName;
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory=beanFactory;       // 讓Bean獲取配置他們的BeanFactory的引用。
    }

    @Override
    public void setBeanName(String beanName) {
        this.beanName=beanName;     // 讓Bean獲取自己在BeanFactory配置中的名字(根據情況是id或者name)
    }
}

  以上兩個set方法Spring會自動調用:

  BeanName:會在Spring自身完成Bean配置之后,且在調用任何Bean生命周期回調(初始化或者銷毀)方法之前就調用這個方法。換言之,在程序中使用BeanFactory.getBean(String beanName)之前,Bean的名字就已經設定好了。所以,程序中可以盡情的使用BeanName而不用擔心它沒有被初始化。

  BeanFactory:可能是在根據某個配置文件創建了一個新工廠之后,Spring才調用這個方法,並把BeanFactory注入到Bean中。 

六、BeanPostProcessor接口

  BeanPostProcessor接口提供了兩個默認實現:

public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

  我們先來看一個例子,代碼如下:

public class User implements InitializingBean,DisposableBean {
    public User(){
        System.out.println("實例化User的構造方法......");
    }
    public void destroy() {
        System.out.println("調用實現DisposableBean的destroy方法....");
    }
    public void afterPropertiesSet() {
        System.out.println("調用實現InitializingBean的afterPropertiesSet方法......");
    }
    public void initUser(){
        System.out.println("執行initMethod方法.....");
    }
    public void destroyUser(){
        System.out.println("執行destroyMethod方法......");
    }
}

public class MyBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        // 這邊只做簡單打印   原樣返回bean
        System.out.println("postProcessBeforeInitialization====" + beanName);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        // 這邊只做簡單打印   原樣返回bean
        System.out.println("postProcessAfterInitialization====" + beanName);
        return bean;
    }
}

@Configuration
public class MainConfig {

    @Bean(initMethod = "initUser", destroyMethod = "destroyUser")
    public User getUser() {
        return new User();
    }

    @Bean
    public MyBeanPostProcessor getMyBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }

    public static void main(String[] args) {
        // 使用AnnotationConfigApplicationContext獲取spring容器ApplicationContext
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        applicationContext.close();
    }
}

  測試結果如下:

實例化User的構造方法......
postProcessBeforeInitialization====getUser
調用實現InitializingBean的afterPropertiesSet方法......
執行initMethod方法.....
postProcessAfterInitialization====getUser
調用實現DisposableBean的destroy方法....
執行destroyMethod方法......

  因此可以總結:

1,首先執行bean的構造方法,
2,BeanPostProcessor的postProcessBeforeInitialization方法
3,InitializingBean的afterPropertiesSet方法
4,@Bean注解的initMethod方法
5,BeanPostProcessor的postProcessAfterInitialization方法
6,DisposableBean的destroy方法
7,@Bean注解的destroyMethod方法

  我們根據源碼進行實例化Bean的確認(銷毀同理):

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    // 省略部分代碼。。。。
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 位置2的 BeanPostProcessor的postProcessBeforeInitialization方法執行的地方 // 這也是為什么他執行所有的初始化之前的原因了
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    try {
        // 初始化bean
 invokeInitMethods(beanName, wrappedBean, mbd);
    } catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 位置5的 BeanPostProcessor的PostProcessorsAfterInitialization方法執行的地方 // 初始化完成之后執行BeanPostProcessor的postProcessorsAfterInitialization
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
        throws Throwable {
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 位置3的 InitializingBean的afterPropertiesSet方法
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }
    if (mbd != null) {
        // 位置4的 @Bean注解的initMethod方法
        String initMethodName = mbd.getInitMethodName();
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

  注意:初始化開始於啟動類AnnotationConfigApplicationContext.refresh()方法;銷毀開始於applicationContext.close()方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM