spring启动流程
1:读取配置信息,将配置的文件信息转换Map<name,beanDefinition>
2:根据上述的Map<name,beanDefinition>去创建bean,并完成依赖注入
Spring MVC
四大组件DispatcherServlet、HandlerMapping、HandlerAdapter以及ViewResolver
启动流程:
1.读取web.xml
2.解析<context-param>里的键值对
3.解析<listener>
4.解析<filter>
5.解析<servlet>
如下图:
dispatcherservlet执行流程:
doService->doDispatch->getHandler(向HandlerMapping请求查找HandlerExecutionChain)->getHandlerAdapter->如果是get请求判断请求头是否有修改,没有修改直接返回->applyPreHandle(按顺序依次执行HandlerInterceptor的preHandle方法)->handle->applyPostHandle(逆序执行HandlerInterceptor的postHandle方法)->processDispatchResult(渲染视图填充Model)
filter是java web的标准,在servlet之前,所以在拦截器之前,里面有一个doFilter方法,拦截前和拦截后都在这里处理,基于入栈出栈模式。
bean实例化流程
bean初始化顺序
Constructor > @PostConstruct > InitializingBean > init-method
循环依赖问题
这个说到注入依赖的三种方式,1.构造器注入;2.set方法注解注入;3.属性注解注入
那如果类A依赖了类B,类B又依赖了类A呢?
如果是构造器注入方式,这个时候创建bean将会异常,启动会报BeanCurrentlyInCreationException异常,
如果是后两种方法注入,bean其实已经通过构造方法创建,只是它的依赖还没注入完成,但这个时候是可以去先注入的,spring通过3级缓存的方式,解决了这种循环依赖,完全创建好的bean放一层,依赖没注入好的放一层,第三层放要被实例化的对象的对象工厂类。
比如:A->B->C-A,首先发现A在一、二层缓存没有,就找到第三层,并创建了一个,然后填充A的时候发下需要B,这个时候类似之前A的过程,然后创建C,填充C的时候发现需要A,就开始从缓存中一层层的找,发现在第三级,然后删除第三级缓存,放入第二级,返回A, 这个时候C就创建好了,C可以放入第一级,同时清理二级和三级缓存的数据。然后B也好了,再然后A也好了。
IOC扩展点
beanfactorypostprocessor 和 beanpostprocessor,是ioc的两个扩展点
BeanFactoryPostProcessor
可以在spring容器加载了bean的定义文件之后,在bean实例化之前执行的,可以修改bean的定义和属性,可以配置多个,然后通过order来控制执行顺序。
BeanPostProcessor
是在bean初始化前后执行的
基础组件
BeanFactory
产生一个新的实例,本质是一个工厂,管理bean
FactoryBean
本质是一个bean,用户可以通过实现该接口定制实例化Bean的逻辑。根据该Bean的Id从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身, 如果要获取FactoryBean对象,可以在id前面加一个&符号来获取。
ApplicationContext
扩展于BeanFactory,拥有更丰富的功能,例如:添加事件发布机制
Resource
bean配置文件,一般为xml文件。可以理解为保存bean信息的文件
BeanDefinition
定义了bean的基本信息,根据它来创造bean
Spring boot starter
1.Spring Boot在启动时扫描项目所依赖的JAR包,寻找包含spring.factories文件的JAR包
2.根据spring.factories配置加载AutoConfigure类
3.根据 @Conditional注解的条件,进行自动配置并将Bean注入Spring Context
Spring boot启动流程
简单的说:
扫描spring.factories文件,初始化Spring容器并启动,在这基础上加入各种扩展点,这些扩展点包括:ApplicationContextInitializer、ApplicationListener以及各种BeanFactoryPostProcessor等等。
启动点
SpringApplicationapp =new SpringApplication(Application.class);
Environment env =app.run(args).getEnvironment();
在SpringApplication构造方法里做了几件事:
1.设置sources
2.初始化webEnvironment,用于判断是不是一个web程序
3.初始化initializers,主要是去spring.factories文件中读取key为ApplicationContextInitializer的value,然后调用createSpringFactoriesInstances创建ApplicationContextInitializer实例。
4.初始化listeners,类似初始化initializers,去spring.factories文件中读取key为ApplicationListener的
5.设置mainApplicationClass,通过获取当前调用栈,找到入口方法main所在的类,并将其复制给SpringApplication对象的成员变量mainApplicationClass
SpringApplication对象的run方法:
1.StopWatch记录程序的运行时间
2.configureHeadlessProperty,设置系统属性java.awt.headless,默认true
3.SpringApplicationRunListeners,spring.factories文件中读取该类型,实际上就是在SpringApplication对象的run方法执行的不同阶段,发布相应的事件给对应的监听器。
4.创建并刷新ApplicationContext,加载使用注解的bean定义
BeanFactoryPostProcessor
父类,子类的类初始化,对象初始化的执行顺序
执行顺序为:父类静态块儿>子类静态块儿>父类块儿>父类构造>子类块儿>子类构造
Servlet的生命周期
通过调用 init () 方法进行初始化。
调用 service() 方法来处理客户端的请求。
通过调用 destroy() 方法终止(结束)。
网友评论