【課程免費分享】4 Spring各種Aware注入的原理與實戰

4、Spring各種Aware注入的原理與實戰

Spring通過接口回調的方式提供了多個非常方便的XXAware接口,方便在開發過程中獲取到Spring上下文核心組件,而且這些XXAware都有一個共同的父接口Aware。Aware都是在bean初始化回調前就進行回調的。在官方文檔中列出了常用的Aware:
enter image description here

舉個例子:當我們需要獲取Application和BeanFactory時,只需要實現對應的Aware接口:

@Component
public class BussinessBean implements ApplicationContextAware, BeanFactoryAware {
private static Logger log = LoggerFactory.getLogger(BussinessBean.class);

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
	log.info("==>setApplicationContext");
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
	log.info("==>setBeanFactory");
}

}

在回調後輸出log,運行後可以看到控制檯輸出的log

INFO  com.cml.chat.lesson.lesson4.BussinessBean - ==>setBeanFactory
INFO  com.cml.chat.lesson.lesson4.BussinessBean - ==>setApplicationContext

非常簡單的使用就完成了Application和BeanFactory的獲取,那麼這個是如何實現的呢?爲什麼是在bean初始化回調前就調用了呢?下面進行原理大剖析,老規矩,以調試的方式獲取到BeanFactoryAware的調用鏈關係
enter image description here

這個回調鏈是不是和BeanPostProcessor的調用鏈非常類似?
進入AbstractAutowireCapableBeanFactory.initializeBean和invokeAwareMethods方法

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged(new PrivilegedAction<Object>() {
			public Object run() {
				invokeAwareMethods(beanName, bean);
				return null;
			}
		}, getAccessControlContext());
	}
	else {
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
		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()) {
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}


	private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
		}
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

是不是非常熟悉?竟然是和BeanPostProcessor調用鏈是相同的(不熟悉的話請先看前面的文章《如何在bean初始化回調前後進行自定義操作》),通過invokeAwareMethods方法調用的時機,這就解釋說明了爲什麼BeanPostProcessor,BeanClassLoaderAware,BeanFactoryAware會在bean初始化回調前就回調了。
不是還有其他多個Aware接口麼,爲什麼這幾個Aware會優先調用?

因爲這幾個Aware都是bean相關的,所以在初始化bean的時候就被調用了。

當bean實現了Aware接口時,初始化後會先進行對應的接口回調,從上面代碼可以看出調用順序BeanNameAware->BeanClassLoaderAware->BeanFactoryAware

目前只有這三個Aware找到了,那麼剩下的呢?
這裏繼續使用萬能的方法查看ApplicationAware的調用鏈:

enter image description here

可以看出ApplicationAware是通過ApplicationContextAwareProcessor進行回調的,

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

}

又是BeanPostProcessor,看來BeanPostProcessor在Spring系統中還是佔據舉足輕重的地位啊。
這裏在bean初始化回調前進行其他Aware接口的回調
可以看出調用順序:EnvironmentAware->EmbeddedValueResolverAware->ResourceLoaderAware->ApplicationEventPublisherAware->MessageSourceAware->ApplicationContextAware

bean相關的aware是在bean工廠初始化的時候就回調了,而且回調傳入的是bean工廠自身。那麼ApplicationContextAwareProcessor的各種Aware實例對象又是從哪裏獲取的呢?又是如何融合到上下文中的呢?在前面的文章《如何在bean初始化回調前後進行自定義操作》中已經有詳細說明了,這裏就不多囉嗦了。

通過ApplicationContextAwareProcessor構造方法,繼續往上查找調用鏈在AbstractApplicationContext.prepareBeanFactory中進行了調用

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	//略...
	// Configure the bean factory with context callbacks.
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	//略...

}

prepareBeanFactory方法在AbstractApplicationContext.refresh中調用

	public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();
		//略。。。
		}

refresh方法是在Spring上下文啓動的時候進行調用的,在SpringBoot中非web環境使用的是AnnotationConfigApplicationContext。通過SpringApplication的createApplicationContext方法獲得

 String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
		+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
 String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
		"org.springframework.web.context.ConfigurableWebApplicationContext" };

	protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			contextClass = Class.forName(this.webEnvironment
					? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
		}
		catch (ClassNotFoundException ex) {
		//略
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

這樣從SpringBoot啓動到Aware接口調用的整個邏輯就分析完畢了。又是一個BeanPostProcessor的妙用。

總結

通過上述的說明,可以得出已知的幾個Aware接口回調順序爲:BeanNameAware->BeanClassLoaderAware->BeanFactoryAware->EnvironmentAware->EmbeddedValueResolverAware->ResourceLoaderAware->ApplicationEventPublisherAware->MessageSourceAware->ApplicationContextAware

除了bean相關的Aware是在bean初始化後進行回調的,剩下的大部分都是通過BeanPostProcessor進行回調處理。現在有沒有發現BeanPostProcessor還真是好用。

實戰

那麼這麼好用,這裏也來自己實現個MyAware。在bean初始化完成後,將ApplicationContext和BeanFactory一起通過Aware回調給所有的MyAware實現類。
首先定義MyAware接口:

public interface MyAware extends Aware {
void setAware(ApplicationContext applicationContext, BeanFactory beanFactory);
}

添加自定義MyAwareProcessor

@Component
public class MyAwareProcessor implements BeanPostProcessor, BeanFactoryAware, ApplicationContextAware {

private ApplicationContext applicationContext;
private BeanFactory beanFactory;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
	this.applicationContext = applicationContext;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
	this.beanFactory = beanFactory;
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	if (bean instanceof MyAware) {
		((MyAware) bean).setAware(applicationContext, beanFactory);
	}
	return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	return bean;
}

}

測試實現類MyAwareTest,這裏只是簡單的輸出ApplicationContext和BeanFactory類名

@Component
public class MyAwareTest implements MyAware {
private static Logger log = LoggerFactory.getLogger(MyAwareTest.class);

@Override
public void setAware(ApplicationContext applicationContext, BeanFactory beanFactory) {
	log.info("MyAwareTest.setAware===>applicationContext:" + applicationContext.getClass().getSimpleName() + ",beanFactory:"
			+ beanFactory.getClass().getSimpleName());
}

}

項目啓動後可以看到輸出log:

com.cml.chat.lesson.lesson4.MyAwareTest - MyAwareTest.setAware===>applicationContext:AnnotationConfigApplicationContext,beanFactory:DefaultListableBeanFactory

這樣一個超簡單的MyAware就實現了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章