Spring5
2022-10-21 14:26:10 4 举报
Spring5源码分析
作者其他创作
大纲/内容
第一阶段:配置阶段
3
循环resources,为每一个资源调用此方法进行定位从特殊的xml文件中载入bean定义
12.3. getLifecycleProcessor().onRefresh();
5
getBean(name)
2
执行了一个针对BeanFactory的刷新动作,关闭了之前的BeanFactory并初始化一个全新的BeanFactory
3. 根据指定名称返回一个已经注册的单例对象,如果没有注册过,则创建并注册一个新的对象并返回。从singletonObjects这个map对象中获取已经注册的单例对象
11. finishBeanFactoryInitialization(beanFactory)实例化单例bean。spring配置的bean默认是非延迟加载的。会调用AbstractBeanFactory的getBean()方法,实际上进入了依赖注入的主流程。
12. finishRefresh();初始化容器的生命周期事件处理器,并发布容器的生命周期事件,在内部实现web策略初始化操作
1
3.2
HandlerAdapter
BeanDefinitionReaderUtils
initStrategies(context);初始化九个策略(组件)
根据Servlet规范,servlet通过service方法接收用户请求。分别传参:HttpServletRequest、HttpServletResponse
此处有校验,若存在BeanFactory,则销毁Bean单例对象,并关闭BeanFactory,然后进行下一步操作
1. initMultipartResolver(context);文件上传解析。如果请求类型是multipart将通过MultipartResolver进行文件上传解析
FrameworkServlet
2.2 loadBeanDefinitions(resources)从特殊的资源中载入bean定义。可以是xml文件、注解等等多种形式
第二阶段:初始化阶段。servlet容器创建一个servlet对象,并通过调用该servlet对象的init方法执行初始化
HttpServlet
3.1 importBeanDefinitionResource()如果元素节点是<import>元素,则进入导入元素解析
ConstructorResolver
真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
通过配置的HandlerAdapter真实的执行请求处理,得到一个ModalAndView对象
2. getBeanFactory()
依赖注入的整个过程分为三个步骤:创建、赋值和注册1. 创建 - 通过反射或者cglib策略读取ioc容器中的BeanDefinition的bean信息,实例化成对应的bean2. 赋值 - 实际的依赖注入。通过递归将不同的属性值注入到bean的属性中3. 注册 - 将完成初始化的bean实例注册到缓存中去,以供下回直接使用spring的依赖注入分为两个步骤,1是创建,2是注入。在这两个过程中,最核心的一个类是`AbstractAutowireCapableBeanFactory`,我们的bean的创建和依赖注入都在这个类中的`doCreateBean`方法中实现。`doCreateBean`方法中调用了两个最主要的方法,一个负责创建bean实例,一个负责对bean实例的属性进行赋值即依赖注入的核心实现。分别是`createBeanInstance`和`populateBean`方法。`createBeanInstance`中根据不同的策略(BeanUtils的反射创建和CGLIB的代理创建)来创建bean实例,`populateBean`针对已经创建的bean实例进行依赖关系的注入,将调用`setPropertyValues`方法进行每一个属性的赋值,过程中使用到递归调用`setPropertyValue`进行注入。当我们完成了bean的创建和所有的属性注入之后,我们就将单例bean通过`DefaultSingletonBeanRegistry`的`addSingleton`方法将创建完毕的单例bean注册到一个叫做`singletonObjects`的ConcurrentHashMap中,这个就是单例缓存。
4
获取事件传送器,并进行事件转发,进行事件处理。SpringMVC会用到此方法初始化策略。通过调用getBean获取对应的之前初始化的监听器
调用FrameworkServlet的内部监听器类执行具体的监听事件ContextRefreshListener
11
doRegisterBeanDefinitions(root)从xml文件的根目录下开始解析
定位和加载:定位读取资源
向IOC容器注册BeanDefinition
2.2
设置配置文件路径,提供给后续的bean定义阅读器使用,用于定位资源。bean定义阅读器的目的是将bean定义载入到bean工厂中
AbstractApplicationContext
service()
解析:解析载入spring定义的beanDefinition
此方法是个抽象方法,用于后续扩展。面向接口开发,面向继承开发,面向扩展开发。
创建bean实例的核心方法
6
SpringMVC是spring框架下的基于servlet规范的对mvc设计模式的一套完整的实现,目的是用于解决web层的请求处理问题。 SpringMVC的实现原理主要有两个阶段:1. 配置和初始化阶段2. 请求处理阶段在配置和初始化阶段中,我们依据servlet规范,在web.xml文件中配置spring提供的DispatcherServlet和对应的拦截路径,然后servlet容器在启动过程当中就会创建一个DispatcherServlet对象,并调用其中的init方法进行初始化。初始化过程中,主要完成两件事情。一是进行IOC容器初始化和非延迟加载的bean的依赖注入。然后就是对DispatcherServlet中的九大组件(策略)进行初始化。这九大组件主要有ViewResolver(处理视图),HandlerMapping对象(处理请求URL和具体的业务controller映射),MultipartResolver(文件上传相关处理)等等。然后到了第二阶段请求处理阶段,首先会调用DispatcherServlet中的doService方法,然后到doDispatcher方法,具体操作就是从handlerMapping中根据请求信息执行对应contoller方法并返回ModalAndView对象,然后根据配置的各种ViewResolver对ModalAndView对象进行相应的处理并发会结果给用户。在spring mvc中用到了很多的设计模式,最主要的就是mvc模式、然后有委派模式、代理模式、模版方法模式等等。
onApplicationEvent(event)
8
委托子类初始化servlet子类(IOC容器初始化)此处采用了双亲委派模式
1. refreshBeanFactory()
DefaultBeanDefinitionDocumentReader
2.3
BeanDefinitionValueResolver
setPropertyValue(pv);
setConfigLocations()
setPropertyValues(new MutablePropertyValues(deepCopy))
prepareBeanFactory()
DefaultSingletonBeanRegistry
invokeBeanFactoryPostProcessors()
CglibSubclassingInstantiationStrategy
5 loadBeanDefinitions(beanFactory)
使用cglib来实例化bean。最终还是使用了反射,但是中间会通过cglib创建一个代理子类进行实例化
2.1 postProcessWebApplicationContext()
BeanUtils.instantiateClass(constructorToUse);
定位string[]类型的资源,以供bean定义信息的载入
通过委派类将xml解析成spring规定的bean定义。将bean定义的载入动作全权交由委派类处理,返回一个BeanDefinitionHolder的封装类对象。
SimpleApplicationEventMulticaster
12
10
开始IOC容器初始化和依赖注入。具体初始化和注入详情见第一章和第二章。此处只列出Web初始化过程中的内容
finishRefresh()
DispatcherServlet
获取具体执行请求处理的处理器的适配器。用于根据方法的参数动态匹配,自动转型
getBean
getHandler()
9
SimpleInstantiationStrategy
7
使用策略模式,调用策略类实现bean的实例化:CGLib和反射两种实例化方式
DefaultListableBeanFactory
2. getSingleton(beanName); 从singletonObjects中获取对象,若没有则从earlySingletonObjects中获取对象,若没有则从singletonFactories中获取ObjectFactory对象,调用他的getObject方法获取bean。如果有bean对象,则直接return,不进行3、4操作。这个就是解决setter方式注入放入循环依赖的问题。
ClassPathXmlApplicationContext
2.1
AbstractRefreshableConfigApplicationContext
3.refresh()
SpringMVC三大阶段:配置、初始化、请求转发
3.3
loadBeanDefinitions(beanDefinitionReader)
<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>class:application.xml</param-value> </init-param></servlet><servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/*</url-pattern></servlet-mapping>
从XML文件中解析bean定义信息
此处循环调用setPropertyValue(pv);对每一个属性进行依赖注入。在注入过程中会存在递归调用setPropertyValue(pv);的情况
loadBeanDefinitions(EncodedResource encodedResource)从特殊的xml文件中载入bean定义。将资源文件转换成InputStream输入IO流。并调用doLoadBeanDefinitions进行真实的载入bean定义操作
2.1 resourceLoader.getResources(location)。定位资源。此处的 resourceLoader 就是在ClassPathXmlApplication初始化时创建的 PathMatchingResourcePatternResolver 对象
obtainFreshBeanFactory() 告诉子类(AbstractRefreshableApplicationContext)刷新Bean工厂,并获取Bean工厂实例
通过配置的ViewResolver对结果视图对象进行处理
XmlBeanDefinitionReader
1. delegate.parseBeanDefinitionElement(ele)
init()
12.2. clearResourceCaches()
AbstractBeanFactory
转换属性值,例如将引用转换为IOC容器中实例化对象引用。内部使用递归调用getBean的方式生成对应的引用对象。
ClassPathXmlApplicationContext()
2. initLocaleResolver(context);本地化解析
初始化bean定义阅读器以便于对上下文的bean定义进行加载
1. createDelegate()创建一个委派类用于具体的解析操作
ioc容器初始化分3个步骤:定位加载、解析和注册。1. 定位 加载是指定位到Resource并将资源加载到内存的Document对象2. 解析是指将读取到的资源信息解析成spring定义的BeanDefinition对象信息。3. 注册是指将解析后的BeanDefinition信息注册到ioc容器中。以ClassPathXmlApplication作为入口,这4个步骤分别对应三个不同的关键类。加载的关键类是XmlBeanDefinitionReader,通过XmlBeanDefinitionReader类的doLoadDocument方法将资源文件信息通过调用JDK标准的JAXP规范的接口读取并封装成Document对象。解析的关键类是BeanDefinnitionParserDelegate,这是一个委派类,通过这个委派类进行bean的解析动作,将bean信息封装到BeanDefinition对象中。最后注册的关键类是DefaultListableBeanFactory,通过这个bean工厂,将beanDefinition对象注册到ioc容器中,所谓的ioc容器就是一个ConcurrentMap对象,注册动作就是put动作。在spring的ioc容器初始化过程中,用到了很多的设计模式,其中有注册登记式的单例模式、模板方法模式、委派模式。当然也灵活的运用了java的OOP思想、面向继承的思想。父类只定义标准,通过不同的子类实现,面向扩展。
5. initHandlerAdapters(context);通过HandlerAdapter进行多类型的参数动态匹配
initApplicationEventMulticaster()
TypedStringValue typedStringValue = (TypedStringValue) value解析字符串类型的属性值
2. preProcessXml()
prepareRefresh() 为容器启动作准备,设置启动时间和同步标识
createWebApplicationContext()
1. beforeSingletonCreation(beanName);在创建单例bean之前,将要创建的beanName存储到singletonsCurrentlyInCreation标识位中this.singletonsCurrentlyInCreation.add(beanName)。构造器注入方式的循环依赖中会在此处抛出异常。
BeanWrapperImpl
1. loadBeanDefinitions(location)循环configLocations,为每一个资源调用此方法进行定位
1. doLoadDocument()定位完成。读取到XML或者其他的资源文件信息,封装到Document对象中。
initServletBean()
12.1. clearResourceCaches()
解析bean标签元素,并封装成BeanDefinitionHolder对象
AbstractAutowireCapableBeanFactory
3. initThemeResolver(context);主题解析
9. initFlashMapManager(context);flash映射管理
第三阶段:请求转发阶段
根据用户请求获取请求处理链对象该对象封装了handler和interceptors
1. BeanUtils.instantiateClass()默认通过反射或者kotlin方式创建一个XmlWebApplicationContext对象
2.2 applyInitializers()
registerListeners()
initMessageSource()
向spring的ioc容器中注册解析到的bean定义,这是bean定义向spring容器注册的入口
1. transformedBeanName(name)根据指定的名称获取被IOC容器托管的bean的名称。
3.1
Spring AOP
7. initRequestToViewNameTranslator(context);是直接解析请求到视图名
DispatcherServlet相关初始化操作。初始化各策略
registerBeanPostProcessors()
HttpServletBean
将bean定义信息载入到指定的bean工厂中
onRefresh()
loadBeanDefinitions(configLocations)
AbstractBeanDefinitionReader
通过tomcat或者其他的servlet容器读取web.xml信息,然后调用init方法,进行Web容器初始化
refresh()
BeanUtils
onRefresh(event.getApplicationContext());
通过阅读器将bean定义载入到bean工厂
2 initFrameworkServlet()
loadBeanDefinitions(Resource resource)
3.2 processAliasRegistration()如果元素节点是<elias>元素,则进入别名元素解析
getHandlerAdapter
8. initViewResolvers(context);通过ViewResolver解析逻辑视图到具体视图实现
4. initHandlerMappings(context);通过HandlerMapping,将请求映射到处理器。通过此handlerMapping进行请求的转发处理
BeanDefinitionParserDelegate
配置DispatcherServlet
Spring 依赖注入时序图:创建、赋值、注册
第三章:SpringMVC
customizeBeanFactory()对创建的Bean工厂进行定制化,如设置启动参数、开启注解的自动装配等
12.4. publishEvent(new ContextRefreshedEvent(this));发布刷新web策略事件
进行属性依赖注入,依赖注入发生的地方,会在BeanWrapperImpl中完成
AbstractXmlApplicationContext
2.2.1
初始化上下文(IOC容器),将返回的context赋值给全局变量webApplicationContext
4. postProcessXml()
initWebApplicationContext()
使用反射进行实例化在BeanUtils中看到具体的调用是ctor.newInstance。spring5使用了新的kotlin来进行实例化。
第二章:Spring依赖注入
doLoadBeanDefinitions()真实的载入bean定义操作,之前的都是些请求转发,资源装配
Spring IOC容器初始化时序图。主要分成三大步骤:定位加载、解析和注册
handle
web.xml
AbstractRefreshableApplicationContext
资源的变化顺序:XML-> Document->Element->BeanDefinition
初始化资源加载处理器 ResourcePatternResolver = new PathMatchingResourcePatternResolver,提供给后续的bean定义阅读器使用。用于定位资源
postProcessBeanFactory()
6. initHandlerExceptionResolvers(context);执行过程中遇到异常之后的处理策略
3. parseBeanDefinitions()通过给定的委派类解析bean定义
2. singletonObject = singletonFactory.getObject();这里采用了模板方法模式。实际是创建单例对象。因为创建的方式不同,singletonFactory是个接口,具体实现看外部调用者。
super(parent)
processDispatchResult
注册:将BeanDefinition注册到IOC容器中
closeBeanFactory() 关闭之前的BeanFactory
initBeanDefinitionReader(beanDefinitionReader)
通过子类DefaultListableBeanFactory的引用调用父类AbstractBeanFactory的方法
Spring初始化最核心的方法,就是refresh()。把所有的Bean都重新构造一遍
destroyBeans() 销毁所有Bean单例对象
第一章:Spring IOC容器初始化
createBeanFactory()创建一个全新的Bean工厂(DefaultListableBeanFactory)
0 条评论
下一页