在对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对象呢,这是本文次要钻研的内容?
- 上文,咱们看了IOC设计要点和设计构造;以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的;容器中寄存的是Bean的定义即BeanDefinition放到beanDefinitionMap中,实质上是一个
-
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解决申请的过程的源码解析。