学习整理的笔记
一、Spring MVC 启动过程
1.1 web 容器初始化过程
- 初始化监听器listener
- 若
listener implement ServletContextListener
, 则调用contextInitialized()
- 初始化filter,调用
init()
- 按照
<load-on-startup>
顺序初始化servlet, 并调用init()
1.2 web.xml配置
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
复制代码
public class ContextLoaderListener extends ContextLoader implements ServletContextListener
复制代码
servlet和Filter初始化前和销毁后,都会给实现了servletContextListener接口的监听器发出相应的通知。
ContextLoadListener类用来创建Spring application context,并且将application context注册到servletContext里面去. 它读取web.xml中配置的context-param中的配置文件,提前在web容器初始化前准备业务对应的Application context;将创建好的Application context放置于ServletContext中,为springMVC部分的初始化做好准备
1.3 DispatchServlet初始化
DispatchServlet将web请求转发给controller层处理,起到控制器的作用
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>xxx.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
复制代码
Spring工作流程描述
-
用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
-
DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
-
DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
-
提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作: HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中 -
Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
-
根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
-
ViewResolver 结合Model和View,来渲染视图
-
将渲染结果返回给客户端。
1.4 IOC 容器初始化过程
待整理
二、Spring bean生命周期
-
Bean实例化与注入(Bean instantion and DI)
- 扫描xml/注解,获取bean 定义
- 实例化bean
- 依赖注入
-
调用实现了Aware接口类的方法(check for spring Awares)
BeanNameAware.setBeanName(String beanId)
BeanFactoryAware.setBeanFactory(BeanFactory beanFactory)
: 可以用这个方法获取到其他BeanApplicationContextAware. setApplicationContext(ApplicationContext applicationContext)
:ApplicationContextAware传入Spring上下文,该方式同样可以实现BeanFactoryAware功能,但比BeanFactoryAware更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法
-
Bean生命周期回调方法(bean creation lifecycle callback)
- BeanPostProcessor/@PostConstruct: BeanPostProcessor经常被用作是Bean内容的更改
postProcessBeforeInitialization(Object obj, String s)
initializingBean.afterPropertiesSet()
- init-method xml
- BeanPostProcessor/@PostConstruct
postAfterInitialization(Object obj, String s)
- BeanPostProcessor/@PostConstruct: BeanPostProcessor经常被用作是Bean内容的更改
-
使用bean
-
销毁bean
- @PreDestroy 执行注解标注的方法
- DisposableBean.destroy()
- destroy-method xml
三、容器类
3.1 扩展:ApplicationListener
那么每当在一个ApplicationEvent发布到 ApplicationContext时, 这个bean得到通知。其实这就是标准的Oberver设计模式
3.2 ApplicationContextAware
先要有spring容器
<!-- 初始化Spring容器,让Spring容器随Web应用的启动而自动启动 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
复制代码
再注册,将bean加入到容器中
<bean class="com.paic.papc.common.util.PapcApplicationUtils"/>
复制代码
public class PapcApplicationUtils implements ApplicationContextAware
复制代码
spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法,这个类就可以方便获得ApplicationContext中的所有bean。
3.3 BeanFactory
spring使用BeanFactory来实例化、配置和管理对象,但是它只是一个接口,里面有一个getBean()方法。我们一般都不直接用BeanFactory,而是用它的实现类ApplicationContext,这个类会自动解析我们配置的applicationContext.xml,然后根据我们配置的bean来new对象,将new好的对象放进一个Map中,键就是我们bean的id,值就是new的对象
3.4 Aware接口
如 BeanFactoryAware,MessageSourceAware,ApplicationContextAware 对于实现了这些Aware接口的bean,在实例化bean时Spring会帮我们注入对应的:BeanFactory, MessageSource,ApplicationContext的实例
3.5 Filter VS Intercepter VS listener
项目 | Filter | intercepter | listener |
---|---|---|---|
原理 | filter接口中的doFilter回调函数,为处理链:chain.doFilter()为前后分界线 | 基于Java反射机制 | |
servlet容器 | 依赖 | 不依赖, 与servlet无关 | 依赖 |
作用域 | 所有配置的请求,包括图片页面等 | 只对Action请求, 在action之前开始,在action完成后结束 | |
访问上下文,栈值对象 | 不可以 | 可以 | |
生命周期 | 只在容器初始化时初始化一次 inti()方法,web应用停止时才销毁 | 多次调用 | 只在容器初始化时初始化一次 ,web应用停止时才销毁 |
执行顺序 | 按Filter在web.xml中的配置顺序 | ||
场景 | 过滤字符编码,登录验证 | 面向切面编程, 比如动态代理就是拦截器的简单实现 | 监听application,session,request对象的活动 |
servlet、filter、listener是配置到web.xml中
web.xml 的加载顺序是:context-param -> listener -> filter -> servlet -> spring
所以如果过滤器中要使用到 bean,可以将spring 的加载 改成 Listener的方式, 则spring bean可以先通过listener提前加载了
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
复制代码
interceptor不配置到web.xml中, spring的拦截器配置到spring.xml中(cloud_core是配置在biz-context.xml 和web-context.xml )
-
servlet
在服务器的运行生命周期为,在第一次请求(或其实体被内存垃圾回收后再被访问)时被加载并执行一次初始化方法,跟着执行正式运行方法,之后会被常驻并每次被请求时直接执行正式运行方法,直到服务器关闭或被清理时执行一次销毁方法后实体销毁。
(1)、装入:启动服务器时加载Servlet的实例;
(2)、初始化:web服务器启动时或web服务器接收到请求时,或者两者之间的某个时刻启动。初始化工作有init()
方法负责执行完成;
(3)、调用:从第一次到以后的多次访问,都是只调用doGet()
或doPost()
方法;
(4)、销毁:停止服务器时调用destroy()
方法,销毁实例。 -
filter
(1)、启动服务器时加载过滤器的实例,并调用init()
方法来初始化实例;
(2)、每一次请求时都只调用方法doFilter()
进行处理;
(3)、停止服务器时调用destroy()
方法,销毁实例。 filter执行是按照web.xml配置的filter-mapping先后顺序进行执行,所以应该先进行编码处理,写在前面 若把filter的具体实现类写入到<filter-class>
中.那么就默认是由容器而非spring管理,就不能直接注入spring实例<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
- DelegatingFilterProxy
DelegatingFilterProxy就是一个对于servlet filter的代理,用这个类的好处主要是通过Spring容器来管理servlet filter的生命周期,如果filter中需要一些Spring容器的实例,可以通过spring直接注入,另外读取一些配置文件这些便利的操作都可以通过Spring来配置实现。
- DelegatingFilterProxy
-
listener
实现了javax.servlet.ServletContextListener
接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。
Listener的生命周期是由servlet容器(例如tomcat)管理的,而servlet容器并不认得@Autowired注解,因此导致实例注入失败. 而spring容器中的bean的生命周期是由spring容器管理的。
只需在web.xml中先配置初始化spring容器的Listener,然后再配置自己的Listener,在自己的Listener中初始化spring的bean
现在监听器使用spring初始化的内容(即bean)
- 声明listener
<listener>
<listener-class>xxx.SubmitListener</listener-class>
</listener>
复制代码
- 实现listener
- Interceptor
以struts的拦截器为例,加载了struts.xml以后,初始化相应拦截器。当action请求来时调用intercept方法,服务器停止销毁interceptor