欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring源码之ApplicationContext(六)

程序员文章站 2022-06-01 13:41:40
...

前言:
Spring的两大容器ApplicationContext与BeanFactory,顾名思义ApplicationContext是应用的上下文,BeanFactory是bean工厂。
但是从代码层面来看ApplicationContext接口是继承了BeanFactory接口的,也就是说两者都有做容器的能力,而ApplicationContext
相对BeanFactory而言他又多了一些其他的功能,所以在我们常用的web应用中,ApplicationContext应用上下文是作为容器的最佳选择,
当然spring也是希望我们这么用的。
本文将简单阐述一下两个容器的区别,着重在源码层面进行分析两个容器的相辅相成及在spring生态中起到的重要作用。

0.简单阐述ApplicationContext与BeanFactory两种容器的区别

1.作用不同,BeanFactory是用来读取bean的配置文件,管理bean的加载,实例化及其整个生命周期并维护其依赖关系
  ApplicationContext除了拥有BeanFactory的所有功能外,还有更完整的供应用使用的框架功能,如国际化,aop,事务等
2.bean的初始化时机不同,BeanFactory在启动的时候不会初始化bean实例,只有在使用bean的时候才会初始化
  ApplicationContext是在启动的时候就初始化了所有的单例bean

综上所述,关于两个容器的选择,则需要按需选取,对于我们常用的web应用,肯定是选取ApplicationContext容器,因为他就是为了应用而生
而在两个容器都可以使用的情况下,我们就结合我们的硬件来考虑,需要占用较小资源的选择BeanFactory,反之选择ApplicationContext

ApplicationContext应用上下文
从字面来看不太好懂,应用就是咱们常说的web应用或者是其他种类的提供服务的一个程序,而上下文咱们可以通俗的理解为他是一个应用的环境或者是容器,意思是拿到这个context对象了,就相当于咱们拥有掌控这个应用的能力了。
如果把应用比作是一个人的话,那么ApplicationContext就是人的大脑或者是思想,他掌控着整个应用的生命周期。

1.1.ApplicationContext的接口继承关系
关于ApplicationContext的接口定义关系如下图,两个直接的继承接口,一个间接的继承接口。
其中ConfigurableApplicationContext从字面来看是具有配置功能的ApplicationContext,主要是为应用上下文提供配置能力
WebApplicationContext是具体web功能的ApplicationContext,他能获取ServletContext
ConfigurableWebApplicationContext是结合上面两个接口的功能,配置ServletContext以及一些其他的web应用配置
Spring源码之ApplicationContext(六)
1.1.1.先上ApplicationContext接口本尊,关于其父接口此处不作详细说明了,有兴趣的可以自行研究

本接口新定义的方法主要有:
    1.getId()获取context的id
    2.getApplicationName()获取应用名称
    3.getStartupDate()获取启动时间
    4.getParent()获取父容器
    5.getAutowireCapableBeanFactory()获取有自动装配能力的BeanFactory
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
   @Nullable
   String getId();
   
   String getApplicationName();
   
   String getDisplayName();
   
   long getStartupDate();
   
   @Nullable
   ApplicationContext getParent();
   
   AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

1.1.2.接下来看ConfigurableApplicationContext,主要提供了几个配置应用上下文的方法

本接口新定义的方法主要有:
    1.setId(String id)设置id
    2.setParent(@Nullable ApplicationContext parent)设置父容器
    3.setEnvironment(ConfigurableEnvironment environment)设置环境变量
    4.ConfigurableEnvironment getEnvironment()获取环境变量,重写了父接口的方法,此处我理解是为了返回
      ConfigurableEnvironment类型的环境变量,这样相当于扩展了Environment。
    5.addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor)添加bean工厂后置处理器
    6.addApplicationListener(ApplicationListener<?> listener)添加监听器
    7.addProtocolResolver(ProtocolResolver resolver)添加协议解析器
   8.refresh()刷新容器
   9.registerShutdownHook()关闭容器,这是一种推荐的关闭方式
   10.close()关闭
   11.isActive()是否活动状态
   12.getBeanFactory()获取BeanFactory
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
    //常量的定义省略不作解释
   void setId(String id);
   void setParent(@Nullable ApplicationContext parent);
   void setEnvironment(ConfigurableEnvironment environment);
   @Override
   ConfigurableEnvironment getEnvironment();
   void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
   void addApplicationListener(ApplicationListener<?> listener);
   void addProtocolResolver(ProtocolResolver resolver);
   void refresh() throws BeansException, IllegalStateException;
   void registerShutdownHook();
   @Override
   void close();
   boolean isActive();
   ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

1.2.ApplicationContext的实现类继承关系
ApplicationContext的实现类按是否可实例化分为:抽象实现类与具体实现类
按功能分类的话可分为:可刷新的与普通的,这里的可刷新是指刷新BeanFactory,每次刷新都会销毁原工厂,创建新工厂
Spring源码之ApplicationContext(六)
1.2.1.先详细解读一下ApplicationContext的第一个抽象实现类AbstractApplicationContext,
此类中的实现了应用上下文的大部分主流程方法.

此抽象类的功能就是对所有接口的方法进行实现,大体的流程这里不作说明,前文已经阐述了
这里值得注意的地方就是在最后部分有三个抽象方法:
    protected abstract void refreshBeanFactory()//刷新BeanFactory
    protected abstract void closeBeanFactory()//关闭BeanFactory
    public abstract ConfigurableListableBeanFactory getBeanFactory()//获取BeanFactory
他们的抽象化我个人认为是为了扩展,这些会在后面几个实现类中体现

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
   //详细源码不贴出来了
}

1.2.2.下面介绍普通的应用上下文GenericApplicationContext,这里的普通就是他在初始化的时候直接new了BeanFactory

1.构造方法,针对不同的用途:
    GenericApplicationContext()//空参,自己new的BeanFactory
    GenericApplicationContext(DefaultListableBeanFactory beanFactory)//传入一个BeanFactory
    GenericApplicationContext(ApplicationContext parent)//传入一个父容器,子容器的BeanFactory还是自己new
    GenericApplicationContext(DefaultListableBeanFactory beanFactory, ApplicationContext parent)//传入父容器与BeanFactory
2.实现了AbstractApplicationContext中的抽象方法
    refreshBeanFactory()//无具体实现内容,只是替换了id
    cancelRefresh()//重写增强方法,将id置为null 
    closeBeanFactory()//将id置为null,没有完全的关闭销毁
   getBeanFactory()//直接返回
   
3.实现了BeanDefinitionRegistry接口
  此接口的作用,顾名思义就是BeanDefinition的注册,所以GenericApplicationContext拥有了操作BeanDefinition的功能,也就完整了作为应用容器的能力
  下面列举比较重要的方法:
      registerBeanDefinition()//注册BeanDefinition,是调用BeanDefinition里面的方法,后面说BeanFactory的时候详细讲解
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	//...
}

1.2.3.具有刷新功能的抽象应用上下文AbstractRefreshableApplicationContext

AbstractRefreshableApplicationContext最大的特点就说有刷新容器上
    在其父类AbstractApplicationContext的refresh()方法被调用时,
    会调用到refreshBeanFactory()方法,进而重新创建一个bean工厂。
    相对于GenericApplicationContext中refreshBeanFactory()方法的实现,该类中增加了销毁原工厂,创建新工厂的功能
    
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
 
    //1.判断context中是否已有BeanFactory
    //2.有的话就销毁,关闭旧的BeanFactory
    //3.创建新的BeanFactory
   @Override
   protected final void refreshBeanFactory() throws BeansException {
      if (hasBeanFactory()) {
         destroyBeans();
         closeBeanFactory();
      }
      try {
         DefaultListableBeanFactory beanFactory = createBeanFactory();
         beanFactory.setSerializationId(getId());
         customizeBeanFactory(beanFactory);
         loadBeanDefinitions(beanFactory);
         synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
         }
      }
      catch (IOException ex) {
         throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
      }
   }
}

1.2.4.其他实现类的用途

1.具有刷新能力的抽象ApplicationContext
AbstractRefreshableApplicationContext的子类
    AbstractRefreshableConfigApplicationContext扩展配置功能
        AbstractRefreshableWebApplicationContext扩展Web功能
            AnnotationConfigWebApplicationContext WEB应用直接可以使用的基于注解的ApplicationContext
            XmlWebApplicationContext WEB应用直接可以使用的基于XML配置的ApplicationContext
        AbstractXmlApplicationContext 基于XML配置的ApplicationContext抽象类
            ClassPathXmlApplicationContext 解析应用根目录的
            FileSystemXmlApplicationContext 解析文件系统目录的
        
2.常规的ApplicationContext
GenericApplicationContext
    GenericXmlApplicationContext 常规的基于xml解析的ApplicationContext
    AnnotationConfigApplicationContext 基于注解配置的ApplicationContext
    GenericWebApplicationContext 常规的web应用的ApplicationContext