1. 程式人生 > >spring--擴充套件點

spring--擴充套件點

擴充套件點:
BeanFactoryPostProcessor構建 BeanFactory後呼叫,此時BeanFactory , BeanDefinition 已經解析完畢。
BeanPostProcessor初始化 Bean 物件時呼叫,所有bean的構建都會呼叫這個介面的兩個方法。兩個方法引數傳入的bean屬性都已經注入完畢。
InitializingBeanBean 例項建立後,所有的屬性注入完畢後呼叫。
定義bean時可以指定init-method  和 destory-method 方法
InstantiationAwareBeanPostProcessor   bean包裝類初始化時呼叫方法

DisposableBeanBean 例項銷燬時呼叫

擴充套件點呼叫順序:
1、呼叫 BeanFactoryPostProcessor 子類的 postProcessBeanFactory() 方法(工廠必須先建立),這裡beanFactory 已經建立,beanDefinition已經解析完畢。
2、呼叫bean 的構造方法。屬性沒有初始化(使用的都是預設值),依賴沒有注入。
3、呼叫 BeanPostProcessor.postProcessBeforeInitialization() 方法。(所有bean初始化都會呼叫)
4、呼叫 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法。(所有bean初始化都會呼叫)
5、呼叫bean 定義的 init-method 方法(具體到某個bean的初始化)。
6、如果bean 實現了 InitializingBean 介面,呼叫 InitializingBean.afterPropertiesSet() 方法(具體到某個bean的初始化)。
7、呼叫 BeanPostProcessor.postProcessAfterInitialization() 方法。(所有bean初始化都會呼叫)
8、呼叫 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法。(所有bean初始化都會呼叫)

9、bean 銷燬,先呼叫 destory-method 方法,如果bean實現了DisposableBean介面,再呼叫DisposableBean.destroy() 方法。

1、BeanFactoryPostProcessor

此介面只有一個方法:
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
所以就是使用ConfigurableListableBeanFactory 進行擴充套件。

擴充套件方式:
這個擴充套件的地方就是呼叫 ConfigurableListableBeanFactory 方法進行擴充套件。
ConfigurableListableBeanFactory 可以分析和修改、預初始化單例Bean,並且可以修改已有的BeanDifinition屬性和型別

呼叫地方:
所有實現介面BeanFactoryPostProcessor 的bean 都在這裡被呼叫
AbstractApplicationContext.invokeBeanFactoryPostProcessors(beanFactory);

使用場景:
修改bean definition
修改注入型別的注入例項

ConfigurableListableBeanFactory 原始碼分析:

public interface ConfigurableListableBeanFactory
		extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {

	/**
	 * 忽略給定型別依賴的自動注入
	 */
	void ignoreDependencyType(Class<?> type);

	/**
	 * 忽略給定介面型別的自動注入
	 *	這種特定方式通常被用於使用其它方式解決應用上下文依賴註冊。如:BeanFactory通過 BeanFactoryAware 註冊,ApplicationContext 通過 ApplicationContextAware 來註冊。
	 *	預設情況只有 BeanFactoryAware 介面是被忽略的。呼叫此方法忽略介面依賴自動注入。
	 */
	void ignoreDependencyInterface(Class<?> ifc);

	/**
	 * 指定依賴的型別,使用 autowiredValue 物件注入。
	 * 預留給 factory/context 型別注入,但是工廠中沒有這類bean 定義。
	 */
	void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);

	/**
	 * 確定指定bean是否有自動注入的資格,被注入到宣告依賴匹配的類的其它bean中
	 */
	boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
			throws NoSuchBeanDefinitionException;

	/**
	 * 獲取bean 的 BeanDefinition,可以訪問屬性值和構造方法引數。
	 * 返回值不是一個副本,是註冊在factory中原始的definition object。意味著可以修改為其它更多的特定型別。
	 */
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * 獲取factory 管理所有bean 的beanName的統一檢視。
	 */
	Iterator<String> getBeanNamesIterator();

	/**
	 * 清除merged bean 定義快取,刪除那些沒有資格進行完整元資料快取的bean。
	 * 當解析的bean definitions被修改了,如呼叫了 BeanFactoryPostProcessor 方法修改了bean definition。
	 * 注意:此時的bean的元資料對已經建立的bean,是要保留的。
	 */
	void clearMetadataCache();

	/**
	 * 凍結所有的 bean definition, 不讓在後面處理修改。
	 */
	void freezeConfiguration();

	/**
	 * 查詢 Configuration 是否被凍結
	 */
	boolean isConfigurationFrozen();

	/**
	 * 確保所有的非惰性單例(non-lazy-init singletons)全部例項化。用於解決迴圈依賴問題。
	 *	如果需要,通過在factory 設定完成時呼叫
	 */
	void preInstantiateSingletons() throws BeansException;

}
在spring 原始碼中有使用 ConfigurableListableBeanFactory 類的方法:
AbstractApplicationContext.refresh() 方法中呼叫的prepareBeanFactory() 方法。
如:PropertyResourceConfigurer   就是一個內建的BeanFactoryPostProcessor實現,實現類是PropertySourcesPlaceholderConfigurer。

測試:

依賴介面及實現
/**
 * 依賴介面
 */
public interface TestServerInterface {
    void m();
}

@Component
public class TestServer2 implements TestServerInterface {

    @Autowired
    private Other o;

    @Override
    public void m() {
        System.out.println("this is server2");
    }

    public Other getO() {
        return o;
    }

    public void setO(Other o) {
        this.o = o;
    }
}

介面實現類依賴的Other 類:

@Component
public class Other {

    public void m(){
        System.out.println("other m");
    }

}

TestServer 依賴 TestServerInterface 子類

@Component
public class TestServer {

    private String name="default";

    @Autowired
    private TestServerInterface t;

    public void test(){
        t.m();
        System.out.println("spring extend test");
    }

    @PostConstruct
    public void before(){
        System.out.println("init-method........");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public TestServerInterface getT() {
        return t;
    }

    public void setT(TestServerInterface t) {
        this.t = t;
    }
}

BeanFactoryPostProcessor  實現類

/**
 * 構建 BeanFactory 完成後呼叫,此時beanFactory 已經建立,beanDefinition已經解析完畢。
 *
 * 可以修改bean
 * 可以獲取beandefinition,修改bean 的配置
 *
 * 引數是ConfigurableListableBeanFactory,體現了不同BeanFactory
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("BeanFactoryPostProcessor------------");

        /**
         * 修改注入型別
         * 如果此bean還依賴其它的bean的話,那麼依賴的bean是null,因為 finishBeanFactoryInitialization 組建bean之間的關係是在這個方法中呼叫的。
         */
        TestServerInterface t = (TestServerInterface)configurableListableBeanFactory.getBean("testServer2");
        configurableListableBeanFactory.registerResolvableDependency(TestServerInterface.class, t);

        //手動注入Other 物件
        TestServer2 t2 = (TestServer2)t;
        t2.setO(configurableListableBeanFactory.getBean(Other.class));

        /**
         * 修改bean 屬性
         */
        //修改beandefinition 的屬性注入
        BeanDefinition tb = configurableListableBeanFactory.getBeanDefinition("testServer");
        MutablePropertyValues propertyValues = tb.getPropertyValues();
        propertyValues.addPropertyValue("name","new name");

        System.out.println("BeanFactoryPostProcessor############");
    }
}

測試程式碼(省)

測試總結:

測試:
1、獲取testServer ,testServer 的name值被修改為 new name
2、介面TestServerInterface 如果有兩個實現類,那麼啟動時就不知道要注入那一個,在postProcessBeanFactory 方法中,定義了此介面使用 name 為 testServer2 的bean 注入,就解決了這個問。
3、在 postProcessBeanFactory()方法中獲取bean,如果還依賴其它的bean的話,那麼依賴的bean是不會被注入的,這個時候就要手動注入了要麼也呼叫一下 configurableListableBeanFactory.registerResolvableDependency()  方法,因為 finishBeanFactoryInitialization()方法才是組建bean之間的關係的地方。(見程式碼手動注入Other)
4、如果有多個BeanFactoryPostProcessor型別的bean,可以使用 @Order()註解來指定呼叫順序。

2、BeanPostProcessor

初始化 Bean 物件時呼叫,所有bean的構建都會呼叫這個介面的兩個方法。兩個方法引數傳入的bean屬性都已經注入完畢。


使用場景:
可以修改bean的屬性,
可以給bean生成一個動態代理例項等等。一些Spring AOP的底層處理也是通過實現BeanPostProcessor來執行代理包裝邏輯的。

BeanPostProcessor 原始碼分析:

public interface BeanPostProcessor {

	/**
	 * 所有 bean 初始化之前呼叫,bean屬性已經被填充,所有屬性及依賴全部注入。
	 * 返回的bean包裝類或者是原始bean。
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * 所有 bean 初始化之後呼叫。所有屬性及依賴全部注入。
	 * 傳入的bean屬性已經被填充。
	 * 返回的bean包裝類或者是原始bean。
	 * 從spring 2.0開始,FactoryBean 會被呼叫兩次,一次是FactoryBean 本身,一次是getObject() 建立bean。
	 * 		
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}
這兩個方法區別就是被呼叫的地方不同,一個是呼叫bean init-method 之前一個是init-method 之後。

AOP 就是對這些擴充套件點的使用。

注:

BeanFactoryPostProcessor.postProcessBeanFactory()呼叫棧

AbstractApplicationContext.refresh() 方法通過呼叫 invokeBeanFactoryPostProcessors(beanFactory);就是呼叫postProcessBeanFactory() 方法的入口。

AbstractApplicationContext.refresh()方法中呼叫的finishBeanFactoryInitialization(beanFactory) 方法中呼叫了preInstantiateSingletons()方法,確保所有的單例都例項化。所以後面的呼叫順序就是在bean例項化之後初始化bean的時候呼叫了。