天天看點

Spring Bean的生命周期管理(中)實作Aware接口

2 bean配置檔案指定init-method、destroy-method

Spring允許我們建立自己的 init 方法和 destroy 方法。隻要在 Bean 的配置檔案中指定

init-method

destroy-method

的值就可以在 Bean 初始化時和銷毀之前執行一些操作。

案例

public class GiraffeService {
    // 通過<bean>的destroy-method屬性指定的銷毀方法
    public void destroyMethod() throws Exception {
        System.out.println("執行配置的destroy-method");
    }
    
    // 通過<bean>的init-method屬性指定的初始化方法
    public void initMethod() throws Exception {
        System.out.println("執行配置的init-method");
    }
}      

配置檔案中的配置:

<bean name="giraffeService" class="com.giraffe.spring.service.GiraffeService" init-method="initMethod" destroy-method="destroyMethod">
</bean>      

自定義的init-method和post-method方法可以抛異常,但不能有參數。

這種方式比較推薦,因為可以自己建立方法,無需将Bean的實作直接依賴于Spring架構。

@PostConstruct、@PreDestroy

這兩個注解均在

javax.annotation

包。

Spring 支援用

@PostConstruct

@PreDestroy

注解指定

init

destroy

方法。

為使注解生效,需在配置檔案中定義

  • org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
  • 或context:annotation-config

public class GiraffeService {

    @PostConstruct
    public void initPostConstruct(){
        System.out.println("執行PostConstruct注解标注的方法");
    }
    @PreDestroy
    public void preDestroy(){
        System.out.println("執行preDestroy注解标注的方法");
    }
}      

配置檔案:

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />      

實作Aware接口

在Bean中使用Spring架構的一些對象

有些時候我們需要在 Bean 的初始化中使用 Spring 架構自身的一些對象來執行一些操作,比如

  • 擷取 ServletContext 的一些參數
  • 擷取 ApplicaitionContext 中的 BeanDefinition 的名字
  • 擷取 Bean 在容器中的名字等等。

為了讓 Bean 可以擷取到架構自身的一些對象,Spring 提供了一組名為Aware的接口。

這些接口均繼承于org.springframework.beans.factory.Aware标記接口,并提供一個将由 Bean 實作的set方法,Spring通過基于setter的依賴注入方式使相應的對象可以被Bean使用。

介紹一些重要的Aware接口:

ApplicationContextAware

獲得ApplicationContext對象,可以用來擷取所有Bean definition的名字。

任何希望被通知它運作的ApplicationContext對象要實作的接口。

例如,當一個對象需要通路一組協作 bean 時。通過 bean 引用進行配置比僅為了bean=查找而實作此接口更有意義!

如果對象需要通路檔案資源,即想要調用getResource ,想要釋出應用程式事件,或者需要通路 MessageSource,也可以實作此接口。 但是,在這種特定場景中,最好實作更具體的ResourceLoaderAware 、 ApplicationEventPublisherAware或MessageSourceAware接口。

請注意,檔案資源依賴項也可以作為org.springframework.core.io.Resource類型的 bean 屬性公開,通過字元串填充,并由 bean 工廠進行自動類型轉換。 這消除了為了通路特定檔案資源而實作任何回調接口的需要。

org.springframework.context.support.ApplicationObjectSupport是應用程式對象的一個友善的基類,實作了這個接口。

實作該接口的類,通過方法setApplicationContext()獲得該對象所運作在的ApplicationContext。一般用于初始化object。

Spring Bean的生命周期管理(中)實作Aware接口

在填充普通 bean 屬性之後但在初始化回調之前調用,例如:

  • org.springframework.beans.factory.InitializingBean.afterPropertiesSet()
  • 或自定義初始化方法

在:

  • ResourceLoaderAware.setResourceLoader
  • ApplicationEventPublisherAware.setApplicationEventPublisher
  • 和MessageSourceAware之後調用(如果适用)。
  • BeanFactoryAware:獲得BeanFactory對象,可以用來檢測Bean的作用域。
  • BeanNameAware:獲得Bean在配置檔案中定義的名字。
  • ResourceLoaderAware:獲得ResourceLoader對象,可以獲得classpath中某個檔案。
  • ServletContextAware:在一個MVC應用中可以擷取ServletContext對象,可以讀取context中的參數。
  • ServletConfigAware: 在一個MVC應用中可以擷取ServletConfig對象,可以讀取config中的參數。
public class GiraffeService implements   ApplicationContextAware,
        ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
        BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware{
         @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("執行setBeanClassLoader,ClassLoader Name = " + classLoader.getClass().getName());
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("執行setBeanFactory,setBeanFactory:: giraffe bean singleton=" +  beanFactory.isSingleton("giraffeService"));
    }
    @Override
    public void setBeanName(String s) {
        System.out.println("執行setBeanName:: Bean Name defined in context="
                + s);
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("執行setApplicationContext:: Bean Definition Names="
                + Arrays.toString(applicationContext.getBeanDefinitionNames()));
    }
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        System.out.println("執行setApplicationEventPublisher");
    }
    @Override
    public void setEnvironment(Environment environment) {
        System.out.println("執行setEnvironment");
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        Resource resource = resourceLoader.getResource("classpath:spring-beans.xml");
        System.out.println("執行setResourceLoader:: Resource File Name="
                + resource.getFilename());
    }
    @Override
    public void setImportMetadata(AnnotationMetadata annotationMetadata) {
        System.out.println("執行setImportMetadata");
    }
}      

BeanPostProcessor

允許自定義修改新 bean 執行個體的工廠鈎子——如檢查标記接口或用代理包裝 bean。

  • 通過标記接口或類似方式填充bean的後置處理器将實作postProcessBeforeInitialization(java.lang.Object,java.lang.String)
  • 而用代理包裝bean的後置處理器通常會實作postProcessAfterInitialization(java.lang.Object,java.lang.String)

Registration

一個ApplicationContext可在其 Bean 定義中自動檢測 BeanPostProcessor Bean,并将這些後置處理器應用于随後建立的任何 Bean。

普通的BeanFactory允許對後置處理器進行程式設計注冊,将它們應用于通過Bean工廠建立的所有Bean。

Ordering

在 ApplicationContext 中自動檢測的 OrderBeanPostProcessor Bean 将根據 PriorityOrdered 和 Ordered 語義進行排序。

相比之下,在BeanFactory以程式設計方式注冊的BeanPostProcessor bean将按注冊順序應用

對于以程式設計方式注冊的後處理器,通過實作 PriorityOrdered 或 Ordered 接口表達的任何排序語義都将被忽略。

對于 BeanPostProcessor bean,并不考慮 @Order 注解。