从以下三个方面进行介绍:
- 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