Spring中ApplicationContext相关接口解析

581 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天,点击查看活动详情

一、ApplicationContextInitializer:在上下文准备阶段,容器刷新之前做一些初始化工作

用于ConfigurableApplicationContext通过调用refresh函数来初始化Spring容器之前的回调函数,通常在web应用中,设计在初始化Spring容器之前调用。例如依赖于容器ConfigurableApplicationContext中的Enviroment来记录一些配置信息或者使一些配置文件生效。

定义
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
    void initialize(C var1);
}
实现
public class DemoApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
 
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        System.err.println("----" + this.getClass().getSimpleName());
    }
}

二、几个context的继承关系

AnnotationConfigApplicationContext 继承了 GenericApplicationContext 继承了 AbstractApplicationContext 实现了 ConfigurableApplicationContext 继承了 ApplicationContext。

image.png

三、AnnotationConfigApplicationContext

AnnotationConfigApplicationContext继承了GenericApplicationContext,就继承了这个通用应用上下文,GenericApplicationContext内部定义了一个DefaultListableBeanFactory实例,GenericApplicationContext实现了BeanDefinitionRegistry接口,所以可以通过AnnotationConfigApplicationContext实例注册beanDefintion,然后调用refresh() 方法来初始化上下文。AnnotationConfigApplicationContext继承AbstractApplicationContext,AbstractApplicationContext提供了ApplicationContext的抽象实现

image.png

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtensionConfig.class);

AnnotationConfigApplicationContext的构造函数主要是创建了Bean定义的读取器和扫描器,然后注册指定的配置类,然后对spring容器进行刷新。

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    private final AnnotatedBeanDefinitionReader reader;
    private final ClassPathBeanDefinitionScanner scanner;

    //默认构造器
    public AnnotationConfigApplicationContext() {
        //在IOC容器中初始化一个 注解bean读取器AnnotatedBeanDefinitionReader
        this.reader = new AnnotatedBeanDefinitionReader(this);
        //在IOC容器中初始化一个 按类路径扫描注解bean的 扫描器
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
        super(beanFactory);
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        //1. 初始化bean读取器和扫描器;
        //调用父类GenericApplicationContext无参构造函数,初始化一个BeanFactory: DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory()
        this();
        //2.注册bean配置类
        this.register(componentClasses);
         //3.刷新上下文
        this.refresh();
    }

register(annotatedClasses)

注册bean配置类, AnnotationConfigApplicationContext容器通过AnnotatedBeanDefinitionReader的register方法实现注解bean的读取,具体源码如下: AnnotationConfigApplicationContext.java中register方法

//按指定bean配置类读取bean
public void register(Class<?>... annotatedClasses) {
   for (Class<?> annotatedClass : annotatedClasses) {
      registerBean(annotatedClass);
   }
}

public void registerBean(Class<?> annotatedClass) {
   doRegisterBean(annotatedClass, null, null, null);
}

//核心实现逻辑
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    //将Bean配置类信息转成容器中AnnotatedGenericBeanDefinition数据结构, AnnotatedGenericBeanDefinition继承自BeanDefinition作用是定义一个bean的数据结构,下面的getMetadata可以获取到该bean上的注解信息
   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    //@Conditional装配条件判断是否需要跳过注册
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
   }
   //@param instanceSupplier a callback for creating an instance of the bean
   //设置回调
   abd.setInstanceSupplier(instanceSupplier);
   //解析bean作用域(单例或者原型),如果有@Scope注解,则解析@Scope,没有则默认为singleton
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
  //作用域写回BeanDefinition数据结构, abd中缺损的情况下为空,将默认值singleton重新赋值到abd
   abd.setScope(scopeMetadata.getScopeName());
  //生成bean配置类beanName
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
   //通用注解解析到abd结构中,主要是处理Lazy, primary DependsOn, Role ,Description这五个注解
   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
  //@param qualifiers specific qualifier annotations to consider, if any, in addition to qualifiers at the bean class level
  // @Qualifier特殊限定符处理,
   if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
         if (Primary.class == qualifier) {
    // 如果配置@Primary注解,则设置当前Bean为自动装配autowire时首选bean
            abd.setPrimary(true);
         }
  else if (Lazy.class == qualifier) {
  //设置当前bean为延迟加载
            abd.setLazyInit(true);
         }
         else {
      //其他注解,则添加到abd结构中
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
         }
      }
   }
  //自定义bean注册,通常用在applicationContext创建后,手动向容器中一lambda表达式的方式注册bean,
  //比如:applicationContext.registerBean(UserService.class, () -> new UserService());
   for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
     //自定义bean添加到BeanDefinition
      customizer.customize(abd);
   }
   //根据beanName和bean定义信息封装一个beanhold,heanhold其实就是一个 beanname和BeanDefinition的映射
   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
  //创建代理对象
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  // BeanDefinitionReaderUtils.registerBeanDefinition 内部通过DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)按名称将bean定义信息注册到容器中,
  // 实际上DefaultListableBeanFactory内部维护一个Map<String, BeanDefinition>类型变量beanDefinitionMap,用于保存注bean定义信息(beanname 和 beandefine映射)
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

register方法重点完成了bean配置类本身的解析和注册,处理过程可以分为以下几个步骤:

  1. 根据bean配置类,使用BeanDefinition解析Bean的定义信息,主要是一些注解信息
  2. Bean作用域的处理,默认缺少@Scope注解,解析成单例
  3. 借助AnnotationConfigUtils工具类解析通用注解
  4. 将bean定义信息已beanname,beandifine键值对的形式注册到ioc容器中

refresh()刷新上下文

   refresh方法在AbstractApplicationContext容器中实现,refresh()方法的作用加载或者刷新当前的配置信息,如果已经存在spring容器,则先销毁之前的容器,重新创建spring容器,载入bean定义,完成容器初始化工作,debug进源码可以看出AnnotationConfigApplicationContext容器是通过调用其父类AbstractApplicationContext的refresh()函数启动整个IoC容器完成对Bean定义的载入。     

AbstractApplicationContext.java中refresh方法的实现代码如下:

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      //1.刷新上下文前的预处理
      prepareRefresh();

      //2.获取刷新后的内部Bean工厂
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      //3.BeanFactory的预准备工作
      prepareBeanFactory(beanFactory);

      try {
         // BeanFactory准备工作完成后,可以做一些后置处理工作,
      // 4.空方法,用于在容器的子类中扩展
         postProcessBeanFactory(beanFactory);

         // 5. 执行BeanFactoryPostProcessor的方法,BeanFactory的后置处理器,在BeanFactory标准初始化之后执行的
         invokeBeanFactoryPostProcessors(beanFactory);

         // 6. 注册BeanPostProcessor(Bean的后置处理器),用于拦截bean创建过程
         registerBeanPostProcessors(beanFactory);

         // 7. 初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
         initMessageSource();

         // 8. 初始化事件派发器
         initApplicationEventMulticaster();

         // 9.空方法,可以用于子类实现在容器刷新时自定义逻辑
         onRefresh();

         // 10. 注册时间监听器,将所有项目里面的ApplicationListener注册到容器中来
         registerListeners();

         // 11. 初始化所有剩下的单实例bean,单例bean在初始化容器时创建,原型bean在获取时(getbean)时创建
         finishBeanFactoryInitialization(beanFactory);

         // 12. 完成BeanFactory的初始化创建工作,IOC容器就创建完成;
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

四、GenericApplicationContext

GenericApplicationContext继承AbstractApplicationContext实现ConfigurableApplicationContext。 GenericApplicationContext通用应用程序上下文实现,该实现内部有一个 DefaultListableBeanFactory 实例。可以采用混合方式处理bean的定义,而不是采用特定的bean定义方式来创建bean。

GenericApplicationContext基本就是对DefaultListableBeanFactory 做了个简易的封装,几乎所有方法都是使用了DefaultListableBeanFactory的方法去实现。

GenericApplicationContext更多是作为一个通用的上下文(通用的IOC容器) 而存在,BeanFactory本质上也就是一个IOC容器,一个用来生产和获取beans的工厂

GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("mybean", MyBean.class);

context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.registerBean(ConfigurationClassPostProcessor.class);

//执行顺序: 1. beanFactory 后处理器,  2. 添加 bean 后处理器, 3. 初始化单例
context.refresh();

context.close();
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	//内部的beanFactory
	private final DefaultListableBeanFactory beanFactory;

	@Nullable
	private ResourceLoader resourceLoader;

	private boolean customClassLoader = false;

	private final AtomicBoolean refreshed = new AtomicBoolean();


	/**
	 * Create a new GenericApplicationContext
            初始化一个BeanFactory
	 * @see #registerBeanDefinition
	 * @see #refresh
	 */
	public GenericApplicationContext() {
	    this.beanFactory = new DefaultListableBeanFactory();
	}
	//......

五、ConfigurableApplicationContext解析

ConfigurableApplicationContext 继承了 ApplicationContext;该接口的主要任务就是配置应用程序上下文功能

image.png

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
    //硬性基础属性配置
    String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
    String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
    String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
    String ENVIRONMENT_BEAN_NAME = "environment";
    String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
    String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
    String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";

    //给应用上下文-容器设置唯一的id
    void setId(String var1);
    //设置父容器
    void setParent(@Nullable ApplicationContext var1);
    //为上下文设置环境变量
    void setEnvironment(ConfigurableEnvironment var1);
    //获取环境变量配置信息
    ConfigurableEnvironment getEnvironment();

    void addBeanFactoryPostProcessor(BeanFactoryPostProcessor var1);

    void addApplicationListener(ApplicationListener<?> var1);

    void setClassLoader(ClassLoader var1);

    void addProtocolResolver(ProtocolResolver var1);

    void refresh() throws BeansException, IllegalStateException;

    void registerShutdownHook();

    void close();

    boolean isActive();

    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

六、ApplicationContext

  • 从ListableBeanFactory接口继承来的:用于访问应用组件的工厂方法,直接父接口对BeanFactory进行很多拓展
  • 从ResourceLoader接口继承来的:用通用的方式加载文件资源
  • 从ApplicationEventPublisher接口继承来的:注册和发布事件
  • 从MessageSource接口继承来的:处理消息,支持国际化
  • ApplicationContext 还继承了 EnvironmentCapable、HierarchicalBeanFactory、ResourcePatternResolver等接口
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

	/**
	 * 返回一个唯一的应用上下文id
	 * @return the unique id of the context, or {@code null} if none
	 */
	@Nullable
	String getId();

	/**
	 * 返回已经部署的该应用上下文的名称.
	 * @return a name for the deployed application, or the empty String by default
	 */
	String getApplicationName();

	/**
	 * 返回此上下文友好的名称---这有什么用呢?
	 * @return a display name for this context (never {@code null})
	 */
	String getDisplayName();

	/**
	 * 返回该上下文第一次被加载的时间戳
	 * @return the timestamp (ms) when this context was first loaded
	 */
	long getStartupDate();

	/**
	 *返回父应用上下文, 如果没有父上下文,该上下文就是在上下文层次的根
	 * @return the parent context, or {@code null} if there is no parent
	 */
	@Nullable
	ApplicationContext getParent();


	AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

}

参考原文