从以下三个方面进行介绍:
- Servlet与Spring MVC之间的关系
- Servlet框架线程是否安全
- Spring MVC是如何完全无web.xml启动的
Spring MVC是基于Servlet实现的封装。
首先回顾下Servlet:
Servlet是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
1、编写一个Java类,实现servlet接口。
2、把开发好的Java类部署到web服务器中。
按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet
创建工程:
IDEA添加如下参数可以防止长时间Build

需要Servlet环境,则进入Servlet的Jar包,两种方式:
1.Tomcat自带的
2.mavne 引入的
在JavaEE项目必须有web.xml,那么为啥在SpringBoot不需要web.xml?
1.xml版本:
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello world");
}
}
xml配置:
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.toov5.servlet01.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
启动并且访问:

注: Servlet线程不安全,单例才会产生共享。使用适合加锁哦
关于过滤器和拦截器:
拦截器与过滤器区别
- 拦截器和过滤器都是基于Aop实现,能够对请求执行之前和之后实现拦截。
- 过滤器是基于Servlet容器实现,对Web请求之前和之后实现拦截
- 拦截器不需要依赖于Servlet、不仅可以实现Web请求还有其他方法拦截等。
SpringMVC拦截器的使用
- 自定义拦截拦截请求Token
preHandle在业务处理器处理请求之前被调用;
postHandle在业务处理器处理请求执行完成后,生成视图之前执行;
afterCompletion在DispatcherServlet完全处理完请求后被调用,可用于清理资源等 。afterCompletion()执行完成后开始渲染页面
拦截器:
/**
* 拦截传递参数中是否有token
*/
public class TokenInterceptor implements HandlerInterceptor {
/**
* 请求方法前置拦截,如果返回True表示会执行目标方法(请求方法) 如果返回false的情况下,则不会执行目标方法
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(">>>preHandle<<<");
//回去token
String token = request.getParameter("token");
if (StringUtils.isEmpty(token)) {
//响应下
response.getWriter().print("not find token");
return false;
}
return true;
}
/**
*
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(">>>>>postHandle<<<<<<<<<");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(">>>afterCompletion<<<");
}
}
配置:
@Configuration
@ComponentScan( basePackages = {"com.toov5.controller","com.toov5.service"})
@EnableWebMvc //等于开启Spring MVC注解方式
@EnableAsync
public class SpringMVCConfig implements WebMvcConfigurer {
/**
* 视图解析器
* @return
*/
@Bean
public InternalResourceViewResolver internalResourceViewResolver(){
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setPrefix("/WEB-INF/view/");
internalResourceViewResolver.setSuffix(".jsp");
return internalResourceViewResolver;
}
//1. 手动注入拦截器到Spring中
@Bean
public TokenInterceptor tokenInterceptor(){
return new TokenInterceptor();
}
//2. 添加拦截器
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor()).addPathPatterns("/**"); // /**表示拦截所有请求 也可以排除某个请求
}
DispatcherServlet
}
注意:使用拦截器一定要关闭EnableWebMvc 否则拦截器不会生效。
ServletContainerInitializer
关于Servlet的接口:ServletContainerInitializer. 涉及到Spring Boot Spring MVC如何实现没有web.xml启动的。
在web容器启动时为提供给第三方组件机会做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能。
每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类。
Servlet容器在初始化时候可以加载一些第三方相关依赖初始化工作,比如
实现接口:
@HandlesTypes(value = MyHandlesType.class)
public class MyServletContainerInitializer implements ServletContainerInitializer {
/**
* 作用是servlet容器初始化加载一些操作 比如第三方依赖信息 手动加载Servlet、监听器、过滤器
* @param set 获取继承该类MyHandersType类所有子类class信息 (官方称之为感兴趣的类)
* @param servletContext
* @throws ServletException
*/
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
// 1.打印所有感兴趣的类型
for (Class<?> c : set) {
System.out.println(c);
}
// 2.servletContext 手动注册过滤器、servlet、监听器
ServletRegistration.Dynamic payServlet = servletContext.addServlet("payServlet", new PayServlet());
payServlet.addMapping("/pay");
}
}
定义类:
public class MyHandlesType {
}
继承类:
public class BookServlet extends MyHandlesType {
}
定义servlet:
public class PayServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().print("this is pay");
}
}
启动并访问
注: tomcat回去META-INF下面读取配置:
tomcat启动时候:


下面搭建Spring mvc的环境:
可以看到引入包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
后

DispatcherServlet是Spring MVC的核心类,客户端所有的请求都转发到DispatcherServlet,最终执行请求定义的方法。其实就是一个Servlet类,无非就是包装来根据URL能够映射找到我们Spring mvc中定义的方法。
源代码分析:

看继承图:

继承FrameworkServlet 继承 HttpServlet
面向对象思想,重写。执行先父类再之类。
请求过来先走Service方法,判断类型 如果是get,执行doGet方法。
流程:HttpServlet Service 判断请求如果Get请求
- getHandler(),通过url路径地址查询到具体的控制请求的方法,如果没有找到情况下直接返回404。
Handler 对应的其实就是我们的控制层类方法
SpringMVC容器 存放当前jvm中所有url映射的路径对应的请求的方法存放到Map集合。
Key:url value:请求方法
SpringMVC映射路径的容器在什么时候被创建呢?Servlet在调用我们的init的方法被创建的。
Handler请求控制层 HandlerMethod 指的请求具体方法。
https://www.cnblogs.com/yanghongfei/p/8507632.html
来源:https://www.cnblogs.com/toov5/p/11874905.html