Spring笔记

2018-06-23  本文已影响0人  Sponge1128

1.Spring整体架构

1)核心容器(Core Container)

2)Data Access/Integration

3)Web
       Web上下文模块建立在应用程序上下文模块之上,为基于WEB的应用程序提供上下文

4)AOP
       提供了一个符合AOP联盟标准的面向切面编程的实现,从而将逻辑代码分开,降低它们之间的耦合性。

5)Test
       支持使用Junit和TestNG对Spring组件进行测试。

2.Bean的生命周期

BeanFactory中bean的生命周期

ApplicationContext中bean的生命周期

3.Bean的作用域

4.资源访问(Resource)

资源抽象接口Resource在Spring框架中起着不可或缺的作用,Spring框架使用Resource装载各种资源,包括配置文件资源、国际化属性文件资源等。

       为了访问不同类型的资源,Resource能够通过"classpath:"、"file"等资源地址前缀识别不同的资源类型,还支持Ant风格带通配符的资源地址。
资源配置地址前缀

Ant风格通配符

       资源加载器ResourceLoader接口仅有一个getResource(String location)方法,仅支持通过带资源类型前缀的资源地址加载文件资源;ResourcePatternResolver扩展了ResourceLoader,支持带资源类型前缀和Ant风格的资源路径表达式;PathMatchingResourcePatternResolver则是Spring标准实现类;

5.BeanFactory和ApplicationContext

1)BeanFactory
BeanFactory是一个类通用工厂,可以创建并管理各种类的对象,下图是BeanFactory的继承体系,主要是通过BeanFactory->HierarchicalBeanFactory->ConfigurableBeanFactory->...->XmlBeanFactory(废弃):

       通过资源加载器ResourceLoader加载Resource资源,在初始化BeanDefinitionReader时指定要用的BeanFactory,使用Resource加载BeanDefinition并启动IoC容器;然后就可以通过getBean方法获取bean,bean的初始化发生在第一次调用时。Spring在DefaultSingletonBeanRegistry提供了一个用于缓存单例bean的缓存器,基于HashMap,单例bean以beanName为键保存在这个HashMap中。

2)ApplicationContext
       由BeanFactory派生而来,通过多个其他的接口扩展了BeanFactory的功能,提供了更多面向实际应用的功能,与BeanFactory不同的是,ApplicationContext在初始化应用上下文的时候就实例化所有单实例的bean。ApplicationContext的类继承体系如下:

3)WebApplicationContext
       专门为Web应用准备的,允许从相对于Web根目录的路径中装载配置文件完成初始化工作,在非Web应用环境下,bean只有singleton和prototype两种作用域,WebApplicationContext添加了3个新的作用域:request、session和global session;


       WebApplicationContext扩展了ApplicationContext,定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE存放WebApplicationContext实例;
       ConfigurableWebApplication扩展了WebApplicationContext,允许通过配置的方式实例化WebApplicationContext:

6.IOC

IoC(控制反转)也被称为DI(依赖注入),让调用类对某一接口实现类的依赖关系由第三方(容器或协作类)注入,以移除调用类对某一接口实现类的依赖。
IoC主要可以划分为3种类型:构造函数注入、属性注入和接口注入。Spring支持构造函数注入和属性注入。

IOC容器的初始化过程:
       IoC容器的初始化由refresh()方法启动,包括BeanDefinition的Resource定位、载入和注册三个基本过程,这里仅仅是IoC容器的初始化过程,不包含依赖注入过程,

IOC的依赖注入

       初始化过程主要是在IoC容器中建立BeanDefinition数据映射,并没有对Bean的依赖关系进行注入,依赖注入的过程是在用户第一次向IoC容器索要bean时触发的,当然也可以通过lazy-init属性让容器完成对bean的预实例化。

Bean的初始化方法

Bean的依赖检查
       在一般情况下,Bean的依赖注入是在应用第一次向容器索取Bean的时候发生,不能保证注入一定能够成功,如果需要重新检查这些依赖关系的有效性,IoC容器中,设计了一个依赖检查特性,在Bean定义中设置dependency-check属性来指导依赖检查模式。具体实现是在AbstractAutowireCapableBeanFactory实现creatBean的过程中完成的,会对Bean的Dependencies属性进行检查,如果不满足要求则抛出异常。

7.AOP

       通过在代理类中包裹切面,核心是JDK动态代理,以动态代理为基础,设计出一系列的AOP的横切实现,比如前置通知、返回通知、异常通知等。Spring AOP需要为目标对象建立代理对象,可以通过JDK的Proxy或者第三方类生成器CGLIB来完成,然后启动代理对象的拦截器来完成各种横切面的织入。Spring在运行时通知对象,只支持方法连接点,不支持字段和构造器连接点

AOP基本术语:

建立AopProxy代理对象
       在Spring的AOP模块中,主要的部分是代理对象的生成,通过调用和配置Spring的ProxyFactoryBean来完成,该类封装了主要代理对象的生成过程,可以使用JDK的Proxy和CGLIB两种生成方式。

1)ProxyFactoryBean生成AopProxy代理对象
       以getObject()方法作为入口,需要对target目标对象增加的增强处理,都通过getObject方法实现了封装。首先对通知器链进行初始化,通知器链封装了一系列的拦截器,在生成代理对象时,根据singleton类型和prototype类型的不同,还需要对代理对象的生成做一个区分;

       AopProxy的接口设计很简单,就是获取Proxy代理对象,在此接口下设计了Cglib2AopProxyJdkDynamicAopProxy两种代理对象的实现,获取Proxy代理对象的方式有两种,一种需要指定ClassLoader,另一种不需要。

       在生成代理对象时,需要三个参数,类装载器、代理接口、Proxy回调方法所在的对象,该对象需要实现InvocationHandler接口,而JdkDynamicAopProxy实现了InvocationHandler接口及其invoke()回调方法,所以可以直接使用。

2)Spring AOP拦截器调用的实现
       Spring AOP通过上述两种不同的代理对象生成方法生成代理对象时,相关的拦截器已经配置到了代理对象中,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。

目标对象方法的调用:若未设置拦截器,则直接调用目标对象的方法,对于JdkDynamicAopProxy,通过AopUtils使用反射机制在invokeJoinpointUsingReflection()方法中实现,首先得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用;对于Cglib2AopProxy,通过其MethodProxy对象来直接完成。

AOP拦截器链的调用:虽然可以使用JDK和CGLIB生成不同的AopProxy代理对象,从而构造不同的回调方法来启动对拦截器链的调用,但对拦截器的调用都是在ReflectiveMethodInvocation中,通过proceed()方法逐个运行拦截器的拦截方法来实现的。不过在运行拦截器的拦截方法之前,会通过对代理方法完成一个匹配判断来决定拦截器是否满足切面增强的要求,即在切点中进行matches的匹配过程,如果满足则从拦截器中获取通知器,并启动拦截器的invoke方法进行切面增强;如果不匹配则递归的调用proceed方法,直到所有拦截器都被运行过,然后直接调用目标对象的实现方法。

配置通知器:拦截器的配置是在代理对象的回调方法中,由advised对象(AdvisedSupport对象)完成的,通过调用其getInterceptorsAndDynamicInterceptionAdvice方法生成拦截器,并且为了提高效率还加入了缓存,即针对目标对象方法的拦截器链在生成后会被缓存,所以只需生成一次。在此方法中生成拦截器链的工作是由advisorChainFactory(DefaultAdvisorChainFactory对象)完成的,此对象实现了拦截器链的获取,具体流程如下:

       拦截器适配和注册完成后,List中的拦截器会被JDK/CGLIB生成的代理对象的回调方法invoke/intercept取得,并启动拦截器的invoke调用,最终触发通知的切面增强;

Advice通知的实现
       在为AopProxy代理对象配置拦截器的实现中,有一个取得拦截器的配置过程,由DefaultAdvisorChainFactory实现,这个工厂类负责生成拦截器链,在它的getInterceptorsAndDynamicInterceptionAdvice方法中,有一个适配和注册的过程,通过配置Spring预先设计好的拦截器,Spring加入了它对AOP实现的处理。

AspectJ的切点表达式

AspectJ指示器 描述
arg() 限制连接点匹配参数为知道类型的执行方法
@args() 限制连接点匹配参数由指定注解标注的执行方法
executuon() 用于匹配是连接点的执行方法
this() 限制连接点匹配AOP代理的bean引用为指定类型的类
target 限制连接点匹配目标对象为指定类型的类
@target() 限制连接点匹配特定的执行对象,这些对象对应的类具有指定类型的注解
within() 限制连接点匹配指定的类型
@within() 限制连接点匹配指定注解所标注的类型
@annotation 限制匹配带有指定注解的连接点

8.Spring MVC

       在自动装配中,不需要对Bean属性做显式的依赖关系声明,只需要配好autowiring属性,IoC容器会根据这个属性的配置,使用反射自动查找属性的类型或者名字,然后基于属性的类型或名字来自动匹配IoC容器中的Bean,从而自动地完成依赖注入。

请求处理流程

8.1 上下文在Web容器中的启动

IoC容器启动的基本过程
       IOC容器的启动过程就是建立上下文的过程,是与ServletContext相伴而生的,同时也是IoC容器在Web应用环境中的具体表现之一。由ContextLoaderListener启动的上下文为根上下文,还有一个与Web MVC相关的上下文用来保存控制器需要的MVC对象。
       在web.xml中配置的ContextLoaderListener,为在Web容器中建立IoC容器服务,其实现了ServletContextListener接口,提供了Servlet生命周期结合的回调,比如contextInitializedcontextDestroyed方法,在contextInitialized的实现方法中完成了WebApplicationContext的建立,具体的载入过程是由ContextLoaderListener交由ContextLoader来完成的,主要是完成在Web容器中建立起双亲IoC容器,以及生成相应的WebApplicationContext并将其初始化。

Web容器中的上下文设计
       在WebApplicationContext中,可以看到ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE常量,用来索引在ServletContext中存储的根上下文,同时提供了getServletContext()方法来获取当前Web容器的Servlet上下文环境。
       在启动过程中,Spring会使用一个默认的WebApplicationContext实现作为IoC容器,即XmlWebApplicationContext,在其初始化过程中,Web容器中的IoC容器被建立起来,该过程与对IoC容器的初始化分析一样,有loadBeanDefinition对BeanDefinition的载入,不过在Web环境中,对BeanDefinition的Resource有特别要求,默认的BeanDefinition的配置路径为/WEB-INF/applicationContext.xml,以一个常量保存在XmlWebApplicationContext中。

ContextLoader的设计与实现
       Web应用程序启动时载入IoC容器的功能是由配置的监听器ContextLoaderListener完成,通过使用ContextLoader完成IoC容器,即WebApplicationContext的初始化。

       此监听器是启动根IoC容器并把它载入到Web容器的地方,生成的根上下文被绑定到Web应用程序的ServletContext上,需要访问根上下文可以从WebApplicationContextUtils类的静态方法getWebApplicationContext中得到。
       ContextLoaderListener实现了ServletContextListener接口,该接口里的函数会结合Web容器的生命周期被调用,它会监听ServletContext事件并作出响应。在服务器启动时,ServletContextListener的contextInitialized被调用;在服务器将要关闭时,contextDestroyed方法被调用。
       在初始化回调中,创建了ContextLoader,并利用它来完成IoC容器的初始化。此根上下文会作为Web容器的唯一实例而存在,如果在初始化过程中,发现已经有根上下文被创建,则抛出异常提示创建失败。根上下文的创建需要设置双亲上下文、ServletContext

8.2 Spring MVC的设计与实现

       在完成对ContextLoaderListener的初始化之后,Web容器开始初始化DispatcherServlet的过程,DispatcherServlet会建立自己的上下文来持有Spring MVC的Bean对象,在建立此IoC容器时,会从ServletContext中得到根上下文作为其双亲上下文。
       DispatcherServlet通过集成FrameworkServletHttpServletBean而继承了HttpServlet,通过使用Servlet API来对HTTP请求进行响应,成为Spring MVC的前端处理器,同时成为MVC模块与Web容器集成的处理前端,其工作大致可以分为两个部分:

DispatcherServlet的启动和初始化

MVC处理HTTP分发请求

①HandlerMapping的配置与设计
       在初始化完成时,在上下文环境中已定义的所有HandlerMapping都已经被加载了,加载的handlerMappings被放在一个List中并被排序,存储着HTTP请求对应的映射数据。List中每一个元素对应一个具体的handlerMapping的配置,一般每个handlerMapping可以持有一系列从URL请求到Controller的映射(使用Map)。通过这些HandlerMapping中定义的映射关系,即URL请求与控制器的对应关系,使Spring MVC应用可以根据HTTP请求确定对应的Controller。
       映射关系是通过接口类HandlerMapping封装的,在HandlerMapping接口中定义getHandler()方法,通过此方法,可以获得与HTTP请求对应的HandlerExecutionChain,其封装了具体的Controller和Interceptor链,通过拦截器给handler对象提供功能增强,同时提供了拦截器链的维护,可以调用addInterceptor()方法为拦截器链增加拦截器。
       例如具体的SimpleUrlHandlerMapping为例,其根据URL映射的方式,注册Handler和Interceptor,从而维护一个反应这种映射关系的handlerMap。注册过程在容器对Bean进行依赖注入时发生,实际上是通过Bean的postProcessor来完成。
       主要是通过其基类AbstractUrlHandlerMapping定义的registerHandler(String urlPath,Object handler)方法,在处理过程中:

②使用HandlerMapping完成请求的映射处理
       在AbstractHandlerMapping中启动getHandler的调用,取得Handler的具体过程在getHandlerInternal(HttpServletRequest request)方法中实现,实现过程包括了从HTTP请求中得到URL,并根据URL到urlMapping中获得handler。

③Spring MVC对HTTP请求的分发处理
       在DispatcherServlet中,对HTTP请求的处理是在doService方法中完成的,实际是其交由doDispatch来完成,包括准备ModelAndView,调用getHandler来响应HTTP请求,然后通过执行Handler的处理来得到返回的ModelAndView结果,最后把该对象交给相应的视图对象去呈现。

上一篇 下一篇

猜你喜欢

热点阅读