关于spring:Spring框架系列6-Spring-IOC实现原理详解之IOC体系结构设计

在对IoC有了初步的认知后,咱们开始对IOC的实现原理进行深刻了解。本文将帮忙你站在设计者的角度去看IOC最顶层的结构设计。@pdai

  • Spring框架系列(6) – Spring IOC实现原理详解之IOC体系结构设计

    • 站在设计者的角度思考设计IOC容器
    • Spring IoC的体系结构设计

      • BeanFactory和BeanRegistry:IOC容器性能标准和Bean的注册

        • BeanFactory定义了IOC 容器基本功能标准?
        • BeanFactory为何要定义这么多层次的接口?定义了哪些接口?
        • 如何将Bean注册到BeanFactory中?BeanRegistry
      • BeanDefinition:各种Bean对象及其互相的关系
      • ApplicationContext:IOC接口设计和实现

        • ApplicationContext接口的设计
        • ApplicationContext接口的实现
    • 参考文章
    • 更多文章

站在设计者的角度思考设计IOC容器

如果让你来设计一个IoC容器,你会怎么设计?咱们初步的通过这个问题,来帮忙咱们更好的了解IOC的设计。

在设计时,首先须要思考的是IOC容器的性能(输出和输入), 承接后面的文章,咱们初步的画出IOC容器的整体性能。

在此基础上,咱们初步的去思考,如果作为一个IOC容器的设计者,主体上应该蕴含哪几个局部:

  • 加载Bean的配置(比方xml配置)

    • 比方不同类型资源的加载,解析成生成对立Bean的定义
  • 依据Bean的定义加载生成Bean的实例,并搁置在Bean容器中

    • 比方Bean的依赖注入,Bean的嵌套,Bean寄存(缓存)等
  • 除了根底Bean外,还有惯例针对企业级业务的特地Bean

    • 比方国际化Message,事件Event等生成非凡的类构造去撑持
  • 对容器中的Bean提供对立的治理和调用

    • 比方用工厂模式治理,提供办法依据名字/类的类型等从容器中获取Bean

(pdai:这种思考的过程才是建设性的,常识体系的构建才是高效的)

Spring IoC的体系结构设计

那么咱们来看下Spring设计者是如何设计IoC并解决这些问题的。

BeanFactory和BeanRegistry:IOC容器性能标准和Bean的注册

Spring Bean的创立是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者治理对象间的依赖关系提供了很多便当和根底服务,在Spring中有许多的IOC容器的实现供用户抉择和应用,这是IOC容器的根底;在顶层的结构设计次要围绕着BeanFactory和xxxRegistry进行:

  • BeanFactory: 工厂模式定义了IOC容器的基本功能标准
  • BeanRegistry: 向IOC容器手工注册 BeanDefinition 对象的办法

其互相关系如下:

咱们再通过几个问题来辅助了解。

BeanFactory定义了IOC 容器基本功能标准?

BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能标准,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。咱们看下BeanFactory接口:

public interface BeanFactory {    
      
    //用于勾销援用实例并将其与FactoryBean创立的bean辨别开来。例如,如果命名的bean是FactoryBean,则获取将返回Factory,而不是Factory返回的实例。
    String FACTORY_BEAN_PREFIX = "&"; 
        
    //依据bean的名字和Class类型等来失去bean实例    
    Object getBean(String name) throws BeansException;    
    Object getBean(String name, Class requiredType) throws BeansException;    
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    //返回指定bean的Provider
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    //查看工厂中是否蕴含给定name的bean,或者内部注册的bean
    boolean containsBean(String name);

    //查看所给定name的bean是否为单例/原型
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    //判断所给name的类型与type是否匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    //获取给定name的bean的类型
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    //返回给定name的bean的别名
    String[] getAliases(String name);
     
}

BeanFactory为何要定义这么多层次的接口?定义了哪些接口?

次要是为了辨别在 Spring 外部在操作过程中对象的传递和转化过程中,对对象的数据拜访所做的限度

有哪些接口呢?

  • ListableBeanFactory:该接口定义了拜访容器中 Bean 根本信息的若干办法,如查看Bean 的个数、获取某一类型 Bean 的配置名、查看容器中是否包含某一 Bean 等办法;
  • HierarchicalBeanFactory:父子级联 IoC 容器的接口,子容器能够通过接口办法拜访父容器; 通过 HierarchicalBeanFactory 接口, Spring 的 IoC 容器能够建设父子层级关联的容器体系,子容器能够拜访父容器中的 Bean,但父容器不能拜访子容器的 Bean。Spring 应用父子容器实现了很多性能,比方在 Spring MVC 中,展示层 Bean 位于一个子容器中,而业务层和长久层的 Bean 位于父容器中。这样,展示层 Bean 就能够援用业务层和长久层的 Bean,而业务层和长久层的 Bean 则看不到展示层的 Bean。
  • ConfigurableBeanFactory:是一个重要的接口,加强了 IoC 容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等办法;
  • ConfigurableListableBeanFactory: ListableBeanFactory 和 ConfigurableBeanFactory的交融;
  • AutowireCapableBeanFactory:定义了将容器中的 Bean 按某种规定(如按名字匹配、按类型匹配等)进行主动拆卸的办法;

如何将Bean注册到BeanFactory中?BeanRegistry

Spring 配置文件中每一个<bean>节点元素在 Spring 容器里都通过一个 BeanDefinition 对象示意,它形容了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注册 BeanDefinition 对象的办法。

BeanDefinition:各种Bean对象及其互相的关系

Bean对象存在依赖嵌套等关系,所以设计者设计了BeanDefinition,它用来对Bean对象及关系定义;咱们在了解时只须要抓住如下三个要点:

  • BeanDefinition 定义了各种Bean对象及其互相的关系
  • BeanDefinitionReader 这是BeanDefinition的解析器
  • BeanDefinitionHolder 这是BeanDefination的包装类,用来存储BeanDefinition,name以及aliases等。
  • BeanDefinition

SpringIOC容器治理了咱们定义的各种Bean对象及其互相的关系,Bean对象在Spring实现中是以BeanDefinition来形容的,其继承体系如下

  • BeanDefinitionReader

Bean 的解析过程非常复杂,性能被分的很细,因为这里须要被扩大的中央很多,必须保障有足够的灵活性,以应答可能的变动。Bean 的解析次要就是对 Spring 配置文件的解析。这个解析过程次要通过下图中的类实现:

  • BeanDefinitionHolder

BeanDefinitionHolder 这是BeanDefination的包装类,用来存储BeanDefinition,name以及aliases等

ApplicationContext:IOC接口设计和实现

IoC容器的接口类是ApplicationContext,很显然它必然继承BeanFactory对Bean标准(最根本的ioc容器的实现)进行定义。而ApplicationContext示意的是利用的上下文,除了对Bean的治理外,还至多应该蕴含了

  • 拜访资源: 对不同形式的Bean配置(即资源)进行加载。(实现ResourcePatternResolver接口)
  • 国际化: 反对信息源,能够实现国际化。(实现MessageSource接口)
  • 利用事件: 反对利用事件。(实现ApplicationEventPublisher接口)

ApplicationContext接口的设计

咱们来看下ApplicationContext整体构造

  • HierarchicalBeanFactory 和 ListableBeanFactory: ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基础上,还通过多个其余的接口扩大了 BeanFactory 的性能:
  • ApplicationEventPublisher:让容器领有公布利用上下文事件的性能,包含容器启动事件、敞开事件等。实现了 ApplicationListener 事件监听接口的 Bean 能够接管到容器事件 , 并对事件进行响应解决 。 在 ApplicationContext 形象实现类AbstractApplicationContext 中,咱们能够发现存在一个 ApplicationEventMulticaster,它负责保留所有监听器,以便在容器产生上下文事件时告诉这些事件监听者。
  • MessageSource:为利用提供 i18n 国际化音讯拜访的性能;
  • ResourcePatternResolver : 所 有 ApplicationContext 实现类都实现了相似于PathMatchingResourcePatternResolver 的性能,能够通过带前缀的 Ant 格调的资源文件门路装载 Spring 的配置文件。
  • LifeCycle:该接口是 Spring 2.0 退出的,该接口提供了 start()和 stop()两个办法,次要用于管制异步处理过程。在具体应用时,该接口同时被 ApplicationContext 实现及具体 Bean 实现, ApplicationContext 会将 start/stop 的信息传递给容器中所有实现了该接口的 Bean,以达到治理和管制 JMX、任务调度等目标。

ApplicationContext接口的实现

在思考ApplicationContext接口的实现时,要害的点在于,不同Bean的配置形式(比方xml,groovy,annotation等)有着不同的资源加载形式,这便衍生除了泛滥ApplicationContext的实现类。

第一,从类结构设计上看, 围绕着是否须要Refresh容器衍生出两个抽象类

  • GenericApplicationContext: 是初始化的时候就创立容器,往后的每次refresh都不会更改
  • AbstractRefreshableApplicationContext: AbstractRefreshableApplicationContext及子类的每次refresh都是先革除已有(如果不存在就创立)的容器,而后再从新创立;AbstractRefreshableApplicationContext及子类无奈做到GenericApplicationContext混合搭配从不同源头获取bean的定义信息

第二, 从加载的源来看(比方xml,groovy,annotation等), 衍生出泛滥类型的ApplicationContext, 典型比方:

  • FileSystemXmlApplicationContext: 从文件系统下的一个或多个xml配置文件中加载上下文定义,也就是说零碎盘符中加载xml配置文件。
  • ClassPathXmlApplicationContext: 从类门路下的一个或多个xml配置文件中加载上下文定义,实用于xml配置的形式。
  • AnnotationConfigApplicationContext: 从一个或多个基于java的配置类中加载上下文定义,实用于java注解的形式。
  • ConfigurableApplicationContext: 扩大于 ApplicationContext,它新减少了两个次要的办法: refresh()和 close(),让 ApplicationContext 具备启动、刷新和敞开利用上下文的能力。在利用上下文敞开的状况下调用 refresh()即可启动利用上下文,在曾经启动的状态下,调用 refresh()则革除缓存并从新装载配置信息,而调用close()则可敞开利用上下文。这些接口办法为容器的管制治理带来了便当,但作为开发者,咱们并不需要过多关怀这些办法。

第三, 更进一步了解

设计者在设计时AnnotationConfigApplicationContext为什么是继承GenericApplicationContext? 因为基于注解的配置,是不太会被运行时批改的,这意味着不须要进行动静Bean配置和刷新容器,所以只须要GenericApplicationContext。

而基于XML这种配置文件,这种文件是容易批改的,须要动态性刷新Bean的反对,所以XML相干的配置必然继承AbstractRefreshableApplicationContext; 且存在多种xml的加载形式(地位不同的设计),所以必然会设计出AbstractXmlApplicationContext, 其中蕴含对XML配置解析成BeanDefination的过程。

那么仔细的你从上图能够发现AnnotationWebConfigApplicationContext却是继承了AbstractRefreshableApplicationContext而不是GenericApplicationContext, 为什么AnnotationWebConfigApplicationContext继承自AbstractRefreshableApplicationContext呢 ? 因为用户能够通过ApplicationContextInitializer来设置contextInitializerClasses(context-param / init-param), 在这种状况下用户偏向于刷新Bean的,所以设计者抉择让AnnotationWebConfigApplicationContext继承了AbstractRefreshableApplicationContext。(如下是源码中Spring设计者对它的解释)

 * <p>As an alternative to setting the "contextConfigLocation" parameter, users may
 * implement an {@link org.springframework.context.ApplicationContextInitializer
 * ApplicationContextInitializer} and set the
 * {@linkplain ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM "contextInitializerClasses"}
 * context-param / init-param. In such cases, users should favor the {@link #refresh()}
 * and {@link #scan(String...)} methods over the {@link #setConfigLocation(String)}
 * method, which is primarily for use by {@code ContextLoader}.

咱们把之前的设计要点和设计构造联合起来看:

到此,根本能够<mark>帮忙你从顶层构建对IoC容器的设计了解,而不是过早沉溺于代码的细节</mark>; 所以《Java全栈常识体系》最大的指标是帮忙你构筑体系化的认知,如果你本人去看源码而不站在顶层设计角度登程, 你多半会捡了芝麻丢了西瓜,工夫一长啥印象没有。@pdai

参考文章

https://www.cnblogs.com/ITtan…

更多文章

首先, 从Spring框架的整体架构和组成对整体框架有个认知。

  • Spring根底 – Spring和Spring框架组成

    • Spring是什么?它是怎么诞生的?有哪些次要的组件和外围性能呢? 本文通过这几个问题帮忙你构筑Spring和Spring Framework的整体认知。

其次,通过案例引出Spring的外围(IoC和AOP),同时对IoC和AOP进行案例应用剖析。

  • Spring根底 – Spring简略例子引入Spring的外围

    • 上文中咱们简略介绍了Spring和Spring Framework的组件,那么这些Spring Framework组件是如何配合工作的呢?本文次要承接上文,向你展现Spring Framework组件的典型利用场景和基于这个场景设计出的简略案例,并以此引出Spring的外围要点,比方IOC和AOP等;在此基础上还引入了不同的配置形式, 如XML,Java配置和注解形式的差别。
  • Spring根底 – Spring外围之管制反转(IOC)

    • 在Spring根底 – Spring简略例子引入Spring的外围中向你展现了IoC的根底含意,同时以此发散了一些IoC相干知识点; 本节将在此基础上进一步解读IOC的含意以及IOC的应用形式
  • Spring根底 – Spring外围之面向切面编程(AOP)

    • 在Spring根底 – Spring简略例子引入Spring的外围中向你展现了AOP的根底含意,同时以此发散了一些AOP相干知识点; 本节将在此基础上进一步解读AOP的含意以及AOP的应用形式。

基于Spring框架和IOC,AOP的根底,为构建下层web利用,须要进一步学习SpringMVC。

  • Spring根底 – SpringMVC申请流程和案例

    • 前文咱们介绍了Spring框架和Spring框架中最为重要的两个技术点(IOC和AOP),那咱们如何更好的构建下层的利用呢(比方web 利用),这便是SpringMVC;Spring MVC是Spring在Spring Container Core和AOP等技术根底上,遵循上述Web MVC的标准推出的web开发框架,目标是为了简化Java栈的web开发。 本文次要介绍SpringMVC的申请流程和根底案例的编写和运行。

Spring进阶 – IoC,AOP以及SpringMVC的源码剖析

  • Spring进阶 – Spring IOC实现原理详解之IOC体系结构设计

    • 在对IoC有了初步的认知后,咱们开始对IOC的实现原理进行深刻了解。本文将帮忙你站在设计者的角度去看IOC最顶层的结构设计
  • Spring进阶 – Spring IOC实现原理详解之IOC初始化流程

    • 上文,咱们看了IOC设计要点和设计构造;紧接着这篇,咱们能够看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的
  • Spring进阶 – Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    • 上文,咱们看了IOC设计要点和设计构造;以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的;容器中寄存的是Bean的定义即BeanDefinition放到beanDefinitionMap中,实质上是一个ConcurrentHashMap<String, Object>;并且BeanDefinition接口中蕴含了这个类的Class信息以及是否是单例等。那么如何从BeanDefinition中实例化Bean对象呢,这是本文次要钻研的内容?
  • Spring进阶 – Spring AOP实现原理详解之切面实现

    • 前文,咱们剖析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的。本文次要介绍Spring AOP原理解析的切面实现过程(将切面类的所有切面办法依据应用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor,为后续交给代理加强实现做筹备的过程)。
  • Spring进阶 – Spring AOP实现原理详解之AOP代理

    • 上文咱们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面办法依据应用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor)。本文在此基础上持续介绍,代理(cglib代理和JDK代理)的实现过程。
  • Spring进阶 – Spring AOP实现原理详解之Cglib代理实现

    • 咱们在前文中曾经介绍了SpringAOP的切面实现和创立动静代理的过程,那么动静代理是如何工作的呢?本文次要介绍Cglib动静代理的案例和SpringAOP实现的原理。
  • Spring进阶 – Spring AOP实现原理详解之JDK代理实现

    • 上文咱们学习了SpringAOP Cglib动静代理的实现,本文次要是SpringAOP JDK动静代理的案例和实现局部。
  • Spring进阶 – SpringMVC实现原理之DispatcherServlet初始化的过程

    • 前文咱们有了IOC的源码根底以及SpringMVC的根底,咱们便能够进一步深刻了解SpringMVC次要实现原理,蕴含DispatcherServlet的初始化过程和DispatcherServlet解决申请的过程的源码解析。本文是第一篇:DispatcherServlet的初始化过程的源码解析。
  • Spring进阶 – SpringMVC实现原理之DispatcherServlet解决申请的过程

    • 前文咱们有了IOC的源码根底以及SpringMVC的根底,咱们便能够进一步深刻了解SpringMVC次要实现原理,蕴含DispatcherServlet的初始化过程和DispatcherServlet解决申请的过程的源码解析。本文是第二篇:DispatcherServlet解决申请的过程的源码解析。

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据