关于spring:spring1ApplicationContextAware详解

2次阅读

共计 8148 个字符,预计需要花费 21 分钟才能阅读完成。

ApplicationContextAware 详解

一、进入正题

Aware 转义就是 ” 主动的 ”,顾名思义 spring 给咱们主动做了些事件。spring 有很多以 Aware 结尾的类,有 EnvironmentAware、ApplicationContextAware、MessageSourceAware 等。

这里我次要讲一下 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 A aware(主动获取到) 容器。

二、应用

@Service("gatewayService")
public class GatewayServiceImpl implements IGatewayService,ApplicationContextAware {Map<ServiceBeanEnum,IGatewayBo> chargeHandlerMap=new HashMap<ServiceBeanEnum,IGatewayBo>();

    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<Boolean>() {
                        @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> T getBean(String name) {return (T) applicationContext.getBean(name);
    }

    public static <T> T getBean(Class<T> 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 <T> Map<String, T> getBeansByType(Class<T> 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");
    }
}
正文完
 0