Spring5IOC容器解析——BeanFactory、ApplicationContext

BeanFactory

DefaultListableBeanFactory简单容器

此图是默认容器DefaultListableBeanFactory的继承实现关系图:

  • 1、BeanFactory接口:容器顶级接口,提供了容器最基本的能力,包括获取bean,是否包含bean,是否单例,获取bean类型,Bean的别名等方法。

  • 2、ListableBeanFactory接口:BeanFactory的子接口;具有批量获取Bean的能力

  • 3、HierarchicalBeanFactory接口:具有访问父容器的能力。有层次的BeanFactory。

  • 4、AutowireCapableBeanFactory接口:继承BeanFactory,扩展了自动装配能力。这个接口更多的作用是用于于与其他框架集成,把不在spring容器中的Bean加入到Spring容器生命周期管理中来。此接口很少用

  • 5、ConfigurableBeanFactory:定义了BeanFactory的配置。继承HierarchicalBeanFactory和SingletonBeanRegistry接口。实现了此接口的容器,具有层次,单例BeanDefinition注册功能。

  • 6、ConfigurableListableBeanFactory:大融合接口,除了具有上述接口的能外,还具有类加载器、类型转化、属性编辑器、BeanPostProcessor、作用域、bean定义、处理bean依赖关系、bean销毁等功能。

  • 7、SingletonBeanRegistry接口:具有Bean的操作能力,注册、查询、获取Bean数量等能力。注意此处的Bean是实例,区别于BeanDefinition。

  • 8、SimpleAliasRegistry:Bean的别名操作类,实现了AliasRegistry,具有存储Bean别名,注册Bean别名,获取Bean别名的功能,aliasMap属性存储Bean别名。

  • 9、DefaultSingletonBeanRegistry:除了继承了SimpleAliasRegistry的功能外,最重要的是实现了SingletonBeanRegistry接口,具有存储Bean实例、注册Bean、获取Bean的能力。我们定义的被Spring管理的Class类的实例对象,以及实例的之间的相互依赖关系都是存储在此类中,默认常用的容器DefaultListableBeanFactory的Bean的相关能力,就是通过间接继承此类来实现的。

/** Disposable bean instances: bean name to disposable instance. */
private final Map disposableBeans = new LinkedHashMap<>();

/** Map between containing bean names: bean name to Set of bean names that the bean contains. */
private final Map> containedBeanMap = new ConcurrentHashMap<>(16);

/** Map between dependent bean names: bean name to Set of dependent bean names. */
private final Map> dependentBeanMap = new ConcurrentHashMap<>(64);

/** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
private final Map> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
  • 10、FactoryBeanRegistrySupport:提供多工厂Bean的支持,FactoryBean通过其名字我也可以看出是生产Bean的Bean。

  • 11、AbstractBeanFactory抽象类:承上启下,从图中我们看出AbstractBeanFactory通过继承关系继承FactoryBeanRegistrySupport各种能力,而且实现了右边部分接口,已然是比较完备的Bean容器了。AbstractBeanFactory还通过模板模式定义了获取Bean的算法骨架。

  • 12、AbstractAutowireCapableBeanFactory:具有大部分的能力,实现了AbstractBeanFactory定义的模板方法,其中doCreateBean方法逻辑是把一个BeanDefinition变成Bean的过程,这个方法非常重要。通常我们使用类创建对象,直接new出来,spring把BeanDefinition到Bean的过程模板化,留下了很多扩展点,留给使用者可以在不同的时刻自定义BeanDefition创建Bean的过程。

  • 13、DefaultListableBeanFactory常用的默认容器实现,也是spring最常使用的容器类。DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,说明DefaultListableBeanFactory具有存储BeanDefinition、操作BeanDefinition的能力,DefaultListableBeanFactory通过继承关系也具有了Bean的存储操作功能。

小结:

  • 1、BeanFactory体系,接口分明,完美的体现了接口分离原则。
  • 2、BeanFactory体系中有两种存储:一种是BeanDefinition的存储,另一个是Bean的存储。
  • 3、DefaultListableBeanFactory作为最常用的容器类,不但具有BeanDefinition的存储操作功能,而且通过继承具有Bean的存储操作功能的DefaultListableBeanFactory把存储的BeanDefinition通过一定算法创建Bean并存储起来。

BeanDefinition、BeanFactory、Bean三者关系

通过上面的对各个接口、类的认识,我们再来看看三者的关系。

我们向BeanFactory容器中注入一个BeanDefinition。BeanFactory帮我们存储起来。当我们想要得到一个Bean时,BeanFactory 帮我们把BeanDefinition创建成Bean并缓存起来,这个创建过程是可参与的。

  • BeanFactory保存了BeanDefiniton与Bean。
  • BeanFactory具有使用BeanDefinition创建Bean的功能。
  • BeanFactory允许使用者可以干预BeanDefinition生成Bean的功能。

BeanFactory中的扩展点

设计原则之开闭原则说的特别好:说一个软件实体应该通过扩展来实现变化。
很多优秀的框架都有类似的扩展点设计,列如:

  • Tomcat中的Filter
  • Tomcat中的pipline-valve
  • springmvc中的Interceptor

BeanFactory中从BeanDefinition到Bean并不是一下子就完成的,这有一个过程。spring正是在这个过程中留下扩展点来实现BeanDefinition到Bean的过程中的各种自定义变化。

从上面我们得知:AbstractAutowireCapableBeanFactory中有个doCreateBean()正是BeanDefinition到Bean的创建方法,接下来我们看看这个方法有哪些扩展点:

  • 1、xxxAware接口:使Bean可以获得xxx。列如实现了BeanFactoryAware接口的类,可以在该Bean被加载的过程中获取加载该Bean的BeanFactory。
  • 2、BeanPostProcessor:BeanPostProcessor接口定义的两个方法,分别在bean的初始化方法(InitializingBean接口,或者init-method定义)执行的前后执行
  • 3、InitializingBean接口:实现了InitializingBean接口的类,执行afterPropertiesSet
  • 4、自定义的init-method方法。

ApplicationContext高级容器

容器分为两套体系:一套是早期的 BeanFactory 体系;还有一套是现在常用的ApplicationContext,也可称为应用上下文,它继承了 BeanFactory,它除了有 BeanFactory 的功能外,还提供了其他服务,例如事务和 AOP 服务、国际化(il8n)的消息源以及应用程序事件处理等企业级的服务。

Spring支持两种配置方式,在早期都是 XML 配置文件的方式,而现在使用的是注解配置的方式。BeanFactory体系的容器一般用来处理 XML配置文件的方式,而ApplicationContext 体系则都可以处理。

ApplicationContext 是 BeanFactory 子类,它不仅包含 BeanFactory 所有功能,还对其进行了扩展,而我们习惯将 ApplicationContext 称为应用上下文,因为容器只是它的基本功能。

传统的基于XML配置的经典容器:
  • FileSystemXmlApplicationContext:从文件系统加载配置
  • ClassPathXmlApplicationContext:从ClassPath加载配置
  • XmlWebApplicationContext:用于Web应用程序的容器
目前比较流行的基于注解的容器:
  • AnnotationConfigServletWebServerApplicationContext:该类在SpringBoot的boot模块中
  • AnnotationConfigReactiveWebServerApplicationContext:满足响应式的容器需求,该类在SpringBoot的boot模块中。
  • AnnotationConfigApplicationContext:普通的非Web应用使用该容器
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

    // 返回此应用程序上下文的唯一ID
    @Nullable
    String getId();

    // 返回此上下文所属的应用程序名称
    String getApplicationName();

    // 返回应用上下文具像化的类名
    String getDisplayName();

    // 返回第一次加载此上下文时的时间戳
    long getStartupDate();

    // 获取父级应用上下文
    @Nullable
    ApplicationContext getParent();

    // 将 AutowireCapableBeanFactory 接口暴露给外部使用
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

ApplicationContext 自身提供的方法非常简单,但它继承了六个接口,来扩展自身功能:

  • EnvironmentCapable:获取 Environment。
  • ListableBeanFactory、HierarchicalBeanFactory:这是 BeanFactory 体系接口,分别提供 Bean 迭代和访问父容器的功能。
  • MessageSource:支持国际化功能。
  • ApplicationEventPublisher:应用事件发布器,封装事件发布功能的接口。
  • ResourcePatternResolver:该接口继承至 ResourceLoader ,作用是加载多个 Resource。

ApplicationContext 同样提供了非常多的实现类,其又可细分为两大类, ConfigurableApplicationContext 和 WebApplicationContext。

ConfigurableApplicationContext

该接口是比较重要的一个接口,几乎所有的应用上下文都实现了该接口。该接口在ApplicationContext的基础上提供了配置应用上下文的能力,此外提供了生命周期的控制能力。

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {

    // 应用上下文配置时,这些符号用于分割多个配置路径
    String CONFIG_LOCATION_DELIMITERS = ",; \t\n";

    // BeanFactory中,ConversionService类所对应的bean的名字。如果没有此类的实例的话吗,则使用默认的转换规则
    String CONVERSION_SERVICE_BEAN_NAME = "conversionService";

    //LoadTimeWaver类所对应的Bean在容器中的名字。如果提供了该实例,上下文会使用临时的 ClassLoader ,这样,LoadTimeWaver就可以使用bean确切的类型了 
    String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";

    // Environment 类在容器中实例的名字
    String ENVIRONMENT_BEAN_NAME = "environment";

    // System 系统变量在容器中对应的Bean的名字
    String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";

    // System 环境变量在容器中对应的Bean的名字
    String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

    // 设置容器的唯一ID
    void setId(String id);

    // 设置此容器的父容器
    void setParent(@Nullable ApplicationContext parent);

    // 设置容器的 Environment 变量
    void setEnvironment(ConfigurableEnvironment environment);

    // 以 ConfigurableEnvironment 的形式返回此容器的环境变量。以使用户更好的进行配置
    @Override
    ConfigurableEnvironment getEnvironment();

    // 此方法一般在读取应用上下文配置的时候调用,用以向此容器中增加BeanFactoryPostProcessor。增加的Processor会在容器refresh的时候使用。
    void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);

    // 向容器增加一个 ApplicationListener,增加的 Listener 用于发布上下文事件,如 refresh 和 shutdown 等
    void addApplicationListener(ApplicationListener listener);

    // 向容器中注入给定的 Protocol resolver
    void addProtocolResolver(ProtocolResolver resolver);

    // 这是初始化方法,因此如果调用此方法失败的情况下,要将其已经创建的 Bean 销毁。
    // 换句话说,调用此方法以后,要么所有的Bean都实例化好了,要么就一个都没有实例化
    void refresh() throws BeansException, IllegalStateException;

    // 向JVM注册一个回调函数,用以在JVM关闭时,销毁此应用上下文
    void registerShutdownHook();

    // 关闭此应用上下文,释放其所占有的所有资源和锁。并销毁其所有创建好的 singleton Beans
    @Override
    void close();

    // 检测此 FactoryBean 是否被启动过
    boolean isActive();

    // 返回此应用上下文的容器。
    // 千万不要使用此方法来对 BeanFactory 生成的 Bean 做后置处理,因为单例 Bean 在此之前已经生成。
    // 这种情况下应该使用 BeanFactoryPostProcessor 来在 Bean 生成之前对其进行处理
    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

该接口下又有几个重要的实现类:

  • AbstractApplicationContext:这是个抽象类,仅实现了公共的上下文特性。这个抽象类使用了模板方法设计模式,需要具体的实现类去实现这些抽象的方法。
  • GenericApplicationContext:该类继承自 AbstractApplicationContext,是为通用目的设计的,它能加载各种配置文件,例如 xml,properties 等等。它的内部持有一个 DefaultListableBeanFactory 的实例,实现了 BeanDefinitionRegistry 接口,以便允许向其应用任何 bean 的定义的读取器。
  • AnnotationConfigApplicationContext:该类继承自 GenericApplicationContext ,提供了注解配置(例如:@Configuration、@Component等)和类路径扫描(scan方法)的支持。
WebApplicationContext

该接口是专门为 Web 应用准备的,其允许从相对于 Web 根目录的路径中装载配置文件完成初始化。

public interface WebApplicationContext extends ApplicationContext {

    // 整个 Web 应用上下文是作为属性放置在 ServletContext 中的,该常量就是应用上下文在 ServletContext 属性列表中的 key
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

    // 定义了三个作用域的名称
    String SCOPE_REQUEST = "request";
    String SCOPE_SESSION = "session";
    String SCOPE_APPLICATION = "application";

    // 在工厂中的 bean 名称
    String SERVLET_CONTEXT_BEAN_NAME = "servletContext";

    // ServletContext 初始化参数名称
    String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";

    // 在工厂中 ServletContext 属性值环境bean的名称
    String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";

    // 用来获取 ServletContext 对象
    @Nullable
    ServletContext getServletContext();
}

该接口的核心实现类有:

  • ConfigurableWebApplicationContext:该接口同时继承了 WebApplicationContext 和 ConfigurableApplicationContext,提供了 Web 应用上下文的可配置的能力。
  • GenericWebApplicationContext:该类继承自 GenericApplicationContext,实现了 ConfigurableWebApplicationContext。
  • XmlWebApplicationContext:该上下文是使用 Xml 配置文件的方式,不过是在 Web 环境中使用的。
  • AnnotationConfigServletWebServerApplicationContext:该类是被 SpringBoot 扩展而来的,SpringBoot 使用的就是该上下文。

差异对比

从上面可以看出 BeanFactory 是 Sping 框架的基础接口,一般是面向 Spring 本身;而 ApplicationContext 是以 BeanFactory 为基础进行综合能力扩展,用于满足大型业务应用的创建, ApplicationContext 一般面向使用 Sping 框架的开发者。几乎所有的应用场合我们都是直接使用 ApplicationContet 而非底层的 BeanFactory。

下表列出了BeanFactory 和 ApplicationContext 接口和实现所提供的功能:

功能 / 特点 BeanFactory ApplicationContext
Bean 实例化/装配
BeanPostProcessor 自动注册 没有
BeanFactoryPostProcessor 自动注册 没有
MessageSource 便捷访问(针对i18n) 没有
ApplicationEvent 发布 没有

参考:
https://www.cnblogs.com/smallstudent/p/11641173.html

https://www.cnblogs.com/loongk/p/12216526.html

你可能感兴趣的:(Spring5IOC容器解析——BeanFactory、ApplicationContext)