spring(1)-ApplicationContextAware详解
ApplicationContextAware详解
一、进入正题
Aware本义就是"自动的",顾名思义spring给我们自动做了些事情。spring有很多以Aware结尾的类,有EnvironmentAware、ApplicationContextAware、MessageSourceAware等。
【spring(1)-ApplicationContextAware详解】这里我主要讲一下ApplicationContextAware。
如下文引用,ApplicationContextAware的文档可以阅读 Spring Core Technologies 1.4.6 Method Injection 、Spring Core Technologies 1.6.2. ApplicationContextAware
and BeanNameAware
、方法注入
概括一下,就是:
在大多数应用程序场景中,容器中的大多数bean都是单例的。当一个单例bean需要与另一个单例bean协作,或者一个非单例bean需要与另一个非单例bean协作时,通常通过将一个bean定义为另一个bean的属性来处理依赖关系。当bean的生命周期不同时,就会出现问题。假设单例bean A需要使用非单例(原型)bean B,可能是在A的每个方法调用上。容器只创建单例bean A一次,因此只有一次机会设置属性。容器不能在每次需要bean A时都向bean A提供一个新的bean B实例。二、使用
一个解决方案是放弃一些控制反转
。您可以通过实现ApplicationContextAware接口,以及在bean A每次需要bean B实例时对容器进行getBean(“B”)调用,从而使bean Aaware(自动获取到)
容器。
@Service("gatewayService")
public class GatewayServiceImpl implements IGatewayService,ApplicationContextAware {Map chargeHandlerMap=new HashMap();
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
}
在我们需要使用ApplicationContext的服务中实现ApplicationContextAware接口,系统启动时就可以自动给我们的服务注入applicationContext对象,我们就可以获取到ApplicationContext里的所有信息了。
三、原理分析 我们都知道spring的入口方法就在AbstractApplicationContext的refresh()方法,我们先去看看refresh().prepareBeanFactory()方法。
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()));
// 添加ApplicationContextAware的处理器
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);
...
}
也就是说,spring在启动的时候给我们添加了ApplicationContextAwareProcessor这样一个processor,进去看看它的实现:
@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((PrivilegedAction)() -> {
//核心方法,调用aware接口方法
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);
}
//针对实现了ApplicationContextAware的接口,spring都将调用其setApplicationContext,将applicationContext注入到当前bean对象。
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
那ApplicationContextAwareProcessor又是什么时候调用的呢?我们接着往下看,原来refresh()方法中还有个beanFactory.preInstantiateSingletons()方法,里面有这样一段代码:
拿到所有的beanNames,然后依次判断是否需要加载,如果是,则调用getBean(beanName)方法实例化出来。
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean> factory = (FactoryBean>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Boolean run() {
return ((SmartFactoryBean>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
依次查看getBean() ->doGetBean()->createBean()->doCreateBean()方法:
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
} catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
} else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
查看一下initializeBean方法:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
//调用setBeanName() 、setBeanClassLoaderAware、setBeanFactoryAware方法
this.invokeAwareMethods(beanName, bean);
}Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}try {
//调用afterPropertiesSet()方法
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
//这里才是ApplicationContextProcessor的postProcessAfterInitialization()执行入口:
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}return wrappedBean;
}
原来AbstractAutowireCapableBeanFactory中的inititalBean()方法就是BeanPostProcessor的调用处。但是像BeanNameAware、BeanFactoryAware不同,是通过initialBean()中的invokeAwareMethods直接调用实现的
四、样例
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.util.Map;
/**
* 通过Spring上下文获取bean工具类
*
* @author moon
*/
public class SpringContextUtils implements ApplicationContextAware {/**
* Spring应用上下文环境
*/
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextUtils.initSpringContext(applicationContext);
}public static ApplicationContext getApplicationContext() {
return applicationContext;
}@SuppressWarnings("unchecked")
public static T getBean(String name) {
return (T) applicationContext.getBean(name);
}public static T getBean(Class clazz) {
return applicationContext.getBean(clazz);
}public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}/**
* 根据class对象返回IOC容器中其对象和其子类的对象。
* 未找到则返回空MAP。
* KEY为BEAN ID或者NAME,VALUE为BEAN实例
*
* @param type 需要找的bean类型的CLASS对象
* @return bean映射
*/
public static Map getBeansByType(Class type) {
return BeanFactoryUtils.beansOfTypeIncludingAncestors(SpringContextUtils.getApplicationContext(), type);
}/**
* 初始化ApplicationContext
*
* @param applicationContext 上下文
*/
public static void initSpringContext(ApplicationContext applicationContext) {
SpringContextUtils.applicationContext = applicationContext;
}/**
* 获取业务线(业务线配置在配置文件中)
*
* @return 业务线
*/
public static String getProjectBusinessLine() {
if (applicationContext == null) {
throw new RuntimeException("spring初始化失败");
}
return applicationContext.getEnvironment().getProperty("***.application.businessLine");
}/**
* 获取项目名称(项目名称配置在配置文件中)
*
* @return 项目名称
*/
public static String getProjectName() {
if (applicationContext == null) {
throw new RuntimeException("spring初始化失败");
}
return applicationContext.getEnvironment().getProperty("***.application.name");
}
}
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- spring|spring boot项目启动websocket
- Spring|Spring Boot 整合 Activiti6.0.0
- Spring集成|Spring集成 Mina
- springboot使用redis缓存
- Spring|Spring 框架之 AOP 原理剖析已经出炉!!!预定的童鞋可以识别下发二维码去看了
- Spring|Spring Boot之ImportSelector