引言
上篇文章介紹了BeanPostProcessor的原理,這周加了一週的班,週末靜下心來繼續spring註解式開發的學習。
Spring提供了哪些BeanPostProcessor
spring爲我們提供了很多BeanPostProcessor,使用開發工具可以看到下圖,我們就挑幾個介紹一下
這只是其中的一部分
1.ApplicationContextAwareProcessor的使用
ApplicationContextAwareProcessor是一個Spring內部工具,它實現了接口BeanPostProcessor,用於向實現瞭如下某種Aware接口的bean設置ApplicationContext中相應的屬性:
通過ApplicationContextAwareProcessor源碼中postProcessBeforeInitialization的實現可以看出只要我們的bean組件實現了以下接口就會爲這個bean設置ApplicationContext中相應的屬性:
- EnvironmentAware 用於讀取配置文件中的信息
- EmbeddedValueResolverAware 獲取Spring容器加載的 properties文件屬性值
- ResourceLoaderAware 獲取資源加載器,獲得外部資源文件
- ApplicationEventPublisherAware ApplicationEventPublisherAware事件發佈詳解
- MessageSourceAware Spring的MessageSource的作用
- ApplicationContextAware 獲取IOC容器
那麼如果我們的bean實現了相應的Aware接口,就會去執行invokeAwareInterfaces爲bean設置ApplicationContext中相應的屬性
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
/**
* Create a new ApplicationContextAwareProcessor for the given context.
*/
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
@Override
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>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
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(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);
}
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
那麼我就舉一個實現了ResourceLoaderAware接口的bean做一個測試
ResourceLoaderAware可以用來獲取資源加載器,獲得外部資源文件
//配置類
@Configuration
public class AwareConfig {
@Bean
public MyAwareBean myAwareBean(){
return new MyAwareBean();
}
}
//自定義組件實現ResourceLoaderAware
public class MyAwareBean implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
}
//測試
@Test
public void TestAwareProcessor(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AwareConfig.class);
MyAwareBean bean = applicationContext.getBean(MyAwareBean.class);
ResourceLoader resourceLoader = bean.getResourceLoader();
System.out.println("resourceLoader:"+resourceLoader);
Resource resource=resourceLoader.getResource("classpath:aware-test.txt");
System.out.println("ResourceLoader加載的文件內容是:");
String line=null;
BufferedReader reader=new BufferedReader(new InputStreamReader(resource.getInputStream()));
while((line=reader.readLine())!=null){
System.out.println(line);
}
reader.close();
}
測試結果(文字是aware-test.txt中的類容)
resourceLoader:org.springframework.context.annotation.AnnotationConfigApplicationContext@4c15e7fd: startup date [Sat Jan 12 15:34:33 CST 2019]; root of context hierarchy
ResourceLoader加載的文件內容是:
致橡樹
我如果愛你——
絕不學攀援的凌霄花,借你的高枝炫耀自己;
絕不學癡情的鳥兒,爲綠蔭重複單調的歌曲;
也不止象泉源,常年送來清涼的慰籍;也不止象險峯,
增加你的高度,襯托你的威儀。
甚至日光,甚至春雨,
不,這些都還不夠,我必須是你近旁的一株木棉,
作爲樹的形象和你站在一起。
根,相握在地下;
葉,相觸在雲裏。
每一陣風吹過,我們都互相致意,
但沒有人,聽懂我們的言語。
你有你的銅枝鐵幹,
象刀象劍也象戟;
我有我紅碩的花朵,
象沉重的嘆息,
又象英勇的火炬,
我們分擔寒潮風雷霹靂;我們共享霧靄流嵐虹霓;
彷彿永遠分離,卻又終身相依。
這纔是偉大的愛情,堅貞就在這裏――
愛,不僅愛你偉岸的身軀,
也愛你堅持的位置,足下的土地
其他的就不用舉例了,用法基本都是類似的,主要要了解不同的Aware可以提供什麼功能以及這些功能在開發中的用處,比如這個讀取外部資源的就可以使用配置文件來給屬性賦值,這樣就可以做動態的配置
AutowiredAnnotationBeanPostProcessor介紹
這是一個解析bean中@Autowire註解的類,這個類實現了BeanPostProcessor接口
接下來看一下實現源碼
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
//獲取Autowire元數據
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//將獲取的元素注入到bean中
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
上面的代碼我們先來看findAutowiringMetadata方法,其實這個方法我們可以不用關心,如何獲取Autowire元數可以看看,其中的關鍵代碼就是InjectionMetadata metadata =this.injectionMetadataCache.get(cacheKey);這句話。從這裏我們知道他是從this.injectionMetadataCache,這是一個Map,key爲beanName,value爲注入元數據InjectionMetadata。即直接從這個Map中獲取,那麼接下來我們就要知道這個注入信息是什麼時候放入到這個緩存Map上的。從findAutowiringMetadata代碼上,我們看到this.injectionMetadataCache.put(cacheKey, metadata);這段代碼,這代碼就是把注入信息放到this.injectionMetadataCache上。那麼,從這裏我們可以猜測,在Bean實例化過程中findAutowiringMetadata()這個方法肯定被調用了多次。
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// 獲取緩存的的key
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 根據緩存的key獲取緩存中的metadata,此處我們在開發中也可以借鑑,使用hashMap做緩存來加速計算
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
//此處運用了雙重檢鎖,單例模式也可以使用這種方式來保證線程間的單例模式
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
"] for autowiring metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
當獲取到元數據之後就開調用inject方法注入
public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
Collection<InjectedElement> elementsToIterate =
(this.checkedElements != null ? this.checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
//開始向bean中注入element
element.inject(target, beanName, pvs);
}
}
}
接下來看一下AutowiredFieldElement.inject(target, beanName, pvs);
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
//創建一個依賴描述
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
//獲取要注入的對象
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
//這段代碼使用設置緩存的值的,可以不用關心
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName)) {
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
//當獲取的值不是null時就開始注入
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
到此@Autowire註解大致原理就講完了,其實其中還有很多細節,比如這個註解的的屬性是什麼時機注入到bean中的,後續再補充吧
結束語
下篇文章將介紹屬性賦值和自動裝配