spring组件之ApplicationContext

146 阅读4分钟

注:本系列源码分析基于spring 5.2.2.RELEASE,本文的分析基于 annotation 注解方式,gitee仓库链接:gitee.com/funcy/sprin….

1. ApplicationContext 简介

我们在启动spring容器时,一般像这样启动:

ApplicationContext context = new AnnotationConfigApplicationContext(Main.class);

或这样:

ApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MvcConfig.class);
context.refresh();

这里的 AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext 都是ApplicationContext,最终进行会调用AbstractApplicationContext#refresh方法启动spring容器。

ApplicationContext 翻译为 spring应用上下文,从这个类里可以获取spring运行期间的各种信息,如BeanFactoryEnvironment等,是spring中至关重要的一个类。

ApplicationContext 继承的接口如下:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, 
        HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, 
        ResourcePatternResolver {
    ...
}

从这里可以看到,ApplicationContext 本身也是其他接口的子接口,这些接口的功能如下:

  • EnvironmentCapable:提供了环境配置功能,applicationContext实现中会有一个 Environment 类型的成员变量,可以通过 EnvironmentCapable#getEnvironment() 方法取得
  • ListableBeanFactoryBeanFactory 的子接口,提供了列举BeanFactory中所有bean的方法
  • HierarchicalBeanFactoryBeanFactory 的子接口,提供了BeanFactory类似继承的能力(可以获取父BeanFactory
  • MessageSource:指定消息来源,可以用来实现国际化操作
  • ApplicationEventPublisher:事件发布器,用其提供的publishEvent(...)方法来发布事件
  • ResourcePatternResolver:资源解析器,提供了获取资源(Resource)的方法:getResources(...)

我们来看看ApplicationContext自身提供的方法:

可以看到,它自身的方法并不多。

2. ApplicationContext 继承结构

ApplicationContext家族中,ApplicationContext主要分为两大派系,他们及其代表如下:

  • 非web类型的ApplicationContext:处理普通java应用的ApplicationContext,代表类为AnnotationConfigApplicationContext
  • web类型的ApplicationContext:处理 web 应用的ApplicationContext,代表类为AnnotationConfigWebApplicationContext(这里只考虑servlet类型的web,不考虑reactive的web)

我们再来看看AnnotationConfigApplicationContext的继承结构:

图片来自网络

我们再来看看AnnotationConfigWebApplicationContext的继承结构:

图片来自网络

3. 在bean中获取ApplicationContext

在 spring bean 中获取ApplicationContext,可以通过 ApplicationContextAware 接口来处理:

@Component
public class TestBean implements ApplicationContextAware {

    private ApplicationContext applicationContext;

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

    // 其他操作

}

继承ApplicationContextAware后,ApplicationContextAwareProcessor会在初始化完成后调用setApplicationContext(xxx)方法,这样我们只需要在TestBean中维护一个成员变量,对applicationContext保存即可。

4. ApplicationContextAwareProcessor

ApplicationContextAwareProcessor是一个 BeanPostProcessor,我们主要关注 ApplicationContextAwareProcessor#postProcessBeforeInitialization方法,代表如下:

@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    /**
     * applicationContext 是 Environment、ResourceLoader、
     * ApplicationEventPublisher、MessageSource 等的子类,这些类的aware接口的调用,都可以
     * 通过 applicationContext 参数进行
     */
    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>) () -> {
            invokeAwareInterfaces(bean);
            return null;
        }, acc);
    }
    else {
        invokeAwareInterfaces(bean);
    }
    return bean;
}

/**
 * 调用 Aware 接口的方法
 * 除了EmbeddedValueResolverAware外,其余的传入参数都是 this.applicationContext
 */
private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof EnvironmentAware) {
        ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    }
    if (bean instanceof EmbeddedValueResolverAware) {
        // 注意embeddedValueResolver的获取操作如下:
        // new EmbeddedValueResolver(applicationContext.getBeanFactory());
        ((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的类的 applicationContext
    if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    }
}

这个方法还是比较简单的,就是判断bean类型,然后转换、调用方法。

5. ApplicationContextBeanFactory 的关系

最后我们再来讨论下ApplicationContextBeanFactory 两者的关系。本文一开始就说明了ApplicationContext继承了BeanFactory的接口,因为这两者是继承关系。不过,除了继承关系外,他们还是组合关系,ApplicationContext 持有 BeanFactory 的对象,直接看代码:

对于AnnotationConfigApplicationContextbeanFactory赋值代码如下:

public class GenericApplicationContext extends AbstractApplicationContext 
        implements BeanDefinitionRegistry {

    // 这就是持有的 beanFactory 对象
    private final DefaultListableBeanFactory beanFactory;

    public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }

    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
        return this.beanFactory;
    }

    ...

}

对于 AnnotationConfigWebApplicationContextbeanFactory赋值代码如下:

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

    // 这就是持有的 beanFactory 对象
    @Nullable
    private DefaultListableBeanFactory beanFactory;

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        // 判断当前ApplicationContext是否存在BeanFactory,如果存在的话就销毁所有 Bean,关闭 BeanFactory
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 初始化DefaultListableBeanFactory,看下面的创建方法
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());

            // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
            customizeBeanFactory(beanFactory);

            // 加载 Bean 到 BeanFactory 中
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            ...
        }
    }

    // 创建 beanFactory
    protected DefaultListableBeanFactory createBeanFactory() {
        // 指定父beanFactory
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }

    // 获取 beanFactory
    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
        synchronized (this.beanFactoryMonitor) {
            if (this.beanFactory == null) {
                ...
            }
            return this.beanFactory;
        }
    }

    ...

}

BeanFactory的相关方法实现如下:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {

    ...
    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        assertBeanFactoryActive();
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
        assertBeanFactoryActive();
        return getBeanFactory().getBean(requiredType, args);
    }

    ...
}

这些方法在实现时,都是调用getBeanFactory()获取到BeanFactory对象,然后直接调用BeanFactory的方法,getBeanFactory()调用的就是GenericApplicationContextAnnotationConfigWebApplicationContextgetBeanFactory()方法。

关于ApplicationContext的内容就介绍到这里了。


本文原文链接:my.oschina.net/funcy/blog/… ,限于作者个人水平,文中难免有错误之处,欢迎指正!原创不易,商业转载请联系作者获得授权,非商业转载请注明出处。

本系列的其他文章

【spring源码分析】spring源码分析系列目录