Spring擴展——Aware接口


Aware接口

在Spring中有許多的Aware接口,提供給應用開發者使用,通過Aware接口,我們可以通過set的方式拿到我們需要的bean對象(包括容器中提供的一些對象,ApplicationContext等),根據需要可以將其注入到本地對象的屬性中。
先來看一個Spring兩個基礎的接口

  • BeanPostProcessor
  • BeanFactoryPostProcessor
    簡單來講:
    BeanPostProcessor增加bean的信息,比如 autowaired 或 aware接口注入bean對象的屬性
    BeanFactoryPostProcessor就用於增加BeanDefinition(配置元數據)的信息 比如添加bean的工程,提供一個帶BeanFactory參數的回調接口,說通俗一些就是可以管理我們的bean工廠內所有的beandefinition(未實例化)數據,可以隨心所欲的修改屬性。
    這兩個接口,都是通過bean的形式添加到spring IOC容器中,即它們本身也是作為一種bean,而只不過這兩種bean提供一些特殊的用途而已。
    有區別是的:BeanPostProcessor是在createBean的時候觸發,BeanFactoryPostProcessor會被提前調用用來修改BeanDefinition。

BeanPostProcessor

bean的后置處理器接口,在依賴注入的初始化方法前后進行調用

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;
	}

}

所有Aware接口本身是一種修改bean信息的功能接口,但它自身並不會被觸發,既然是修改bean屬性的功能接口,所以它應該被一個BeanPostProcessor調用———— *AwareProcessor(例如ApplicationContextAwarePostProcessor)
Bean在創建過程,會在實例化后,如果實現了BeanPostProcessor接口,會在實例化后統一調用BeanPostProcessor接口

在我們日常開發中,可以通過在bean中實現ApplicationContextAware的方式將ApplicationContext注入到我們的bean對象中去
在Spring中其實是有一個BeanPostProcessor類——ApplicationContextAwareProcessor,用來處理實現了ApplicationContextAware等接口的bean。
ApplicationContextAware類源碼

public interface ApplicationContextAware extends Aware {

	/**
	 * Set the ApplicationContext that this object runs in.
	 * Normally this call will be used to initialize the object.
	 * <p>Invoked after population of normal bean properties but before an init callback such
	 * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
	 * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
	 * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
	 * {@link MessageSourceAware}, if applicable.
	 * @param applicationContext the ApplicationContext object to be used by this object
	 * @throws ApplicationContextException in case of context initialization errors
	 * @throws BeansException if thrown by application context methods
	 * @see org.springframework.beans.factory.BeanInitializationException
	 */
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

可以看到此aware接口主要是為了在實現類中注入applicationContext,提供這么一個回調方法

ApplicationContextAwareProcessor類源碼

class ApplicationContextAwareProcessor implements BeanPostProcessor {
	private final ConfigurableApplicationContext applicationContext;
	private final StringValueResolver embeddedValueResolver;
	/**
	 * 將Context注入進來
	 */
	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}
	/**
	 * 接口beanPostProcessor規定的方法,會在bean創建時,實例化后,初始化前,對bean對象應用
	 */
	@Override
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
			return bean;
		}
		AccessControlContext acc = null;
		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}
		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				// 檢測bean上是否實現了某個aware接口,有的話進行相關的調用
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

	/**
	 * 如果某個bean實現了某個aware接口,給指定的bean設置相應的屬性值
	 *
	 * @param bean
	 */
	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		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);
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

}

在ApplicationContextAwareProcessor中我們可以看到,其實它處理了好幾個aware接口,所以當我們的Bean只要實現了以下任意的接口,都會在invokeAwareInterfaces方法中被處理

  • EnvironmentAware注入環境屬性,可以拿到系統屬性 環境屬性 ,還有import進去的自定義的屬性文件;
  • EmbeddedValueResolverAware,處理屬性資源中的${}這種表達式,將當前EnvironmentAware中的屬性用來處理${}表達式;
  • ResourceLoaderAware 獲取資源加載器,用它可以動態地添加資源;
  • ApplicationEventPublisherAware 處理事件發布 與ApplicationEvent ApplicationListener一起使用
  • MessageSourceAware 處理資源國際化
  • ApplicationContextAware 注入ApplicationContext,可以getBean等操作

當然看到這個地方,肯定有人會疑惑,這個ApplicationContextAwareProcessor,我們並沒有在代碼中將其實例化為一個Bean。為什么只要實現了ApplicationContextAware接口的Bean對象,就可以注入進來ApplicationContext對象。
其實在Spring源碼中在准備beanFactory的時候就已經將ApplicationContextAwareProcessor添加到beanPostProcessor List列表中了

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		// 添加beanPostProcessor,ApplicationContextAwareProcessor此類用來完成某些Aware對象的注入
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

一、實現SpringUtils工具類

我們希望在自定義的SpringUtils中注入一個ApplicationContext對象,能夠在代碼里通過getBean的形式來獲取IOC容器的中Bean對象
再次感謝spring的開發團隊,因為spring的易擴展性,它為我們提供了超級簡單的方法來獲取applicationContext對象
不多說,看代碼

@Component
public class SpringUtils implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    /**
     * 注入 applicationContext
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    /**
     * 獲取指定類的bean對象
     *
     * @param clazz 類類型
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    /**
     * 獲取指定類的指定名稱的bean對象
     *
     * @param name  bean名稱
     * @param clazz 類類型
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return applicationContext.getBean(name, clazz);
    }
}

一個靜態的SpringUtils就這樣寫好了,是不是So Easy???

二、自定義aware接口,並能夠在bean中自動注入自定義對象

第1步 實現aware接口,定義好需要注入的對象及其相應方法

public interface GlobalSessionAware extends Aware {
    /**
     * 注入全局的session
     *
     * @param session
     */
    public void setGlobalSession(GlobalSession session);
}

第2步 實現BeanPostProcessor,並回調aware接口中的set方法,將BeanPostProcessor作為一個bean對象,加入到spring容器中

@Component
public class GlobalSessionAwarePostProcessor implements BeanPostProcessor, ApplicationContextAware {
    private ApplicationContext applicationContext;
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Object session = this.applicationContext.getBean("globalSession");
        if (session == null) {
            return bean;
        }
        if (session instanceof GlobalSession && bean instanceof GlobalSessionAware) {
            ((GlobalSessionAware) bean).setGlobalSession((GlobalSession) session);
        }
        return bean;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

第3步 使用GlobalSession,在需要注入GlobalSession的bean中實現GlobalSessionAware接口

@Component
public class WebTT implements GlobalSessionAware {
    private GlobalSession session;

    /**
     * GlobalSession
     *
     * @param session
     */
    @Override
    public void setGlobalSession(GlobalSession session) {
        this.session = session;
    }
}

到此已經實現了aware接口的自定義,這個地方我們需要知道的是,Awarer接口本身屬於修改bean信息的一種功能性接口,但它需要在創建bean時能夠被調用到,所以這個地方BeanPostProcessor就能夠實現這個功能


免責聲明!

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



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