SpringMVC执⾏流程及原理
⾯试虐
博主之前每次去⾯试必问的问题:“讲⼀下spring mvc的执⾏流程以及常⽤组件的作⽤”;
记得第⼀次和⾯试官说了⼤概的流程是这样的:“服务器收到⼀个请求后会先去HandlerMapping中匹配url,到url之后⽤HandlerAdapter 适配器去执⾏这个控制器(controller层),执⾏完之后返回⼀个modelAndView,然后通过视图解析器ViewResolver 解析后得到⼀个view对象,这个view就是渲染好的jsp页⾯,返回给前端页⾯”;
(等了⼀会看着我)⾯试官:“ 就这样。。。没啦?”;
懵逼的我:“嗯,没了”;
⾯试官:“那你回家等消息吧!”;
回顾
其实吧,博主说的没错,只是说少了,不够详细,如果是⾯试初级java开发,这样讲是没问题的,妥妥springboot框架的作用
地给过了,但我是谁啊,我可是要成为架构师的⼈啊! 回答出这种答案,⽼板怎么放⼼把项⽬交给我呢。于是啊,吸取了教训,我就在家潜⼼研究,经过七七四⼗九天的研究、九九⼋⼗⼀次的练习,终于让我掌握了这门核⼼技术;
什么是Spring mvc
springMVC是⼀种web层mvc框架;是spring的⼀个模块,拥有spring的特性,通过策略接⼝,Spring框架是⾼度可配置的,⽽且包含多种视图技术,例如 JavaServer Pages(JSP)技术、Velocity、Tiles、iText 和 POI。Spring MVC 框架并不知道使⽤的视图,所以不会强迫您只使⽤ JSP 技术。Spring的MVC框架主要由DispatcherServlet、处理器映射、处理器(控制器)、视图解析器、视图组成。
都知道叫做spring mvc,mvc是什么东东呢?其实就是三层架构, 在过去架构都是两层的,就是浏览器通过servlet后直接访问JSP页⾯,也就是说所有的java代码都是在jsp页⾯⾥⾯写的,就连访问数据库也是在jsp页⾯,⼩型项⽬这样开发没什么问题,因为快嘛,但是⼤型项⽬是需要迭代的,是需要增加功能和模块的,你这么写的话,我后期维护起来很⿇烦啊;⽽且java代码和html标签混搭,这样代码的可读性也不⾼;所以就衍⽣出了MVC三层架构,
M : 表⽰model,翻译成中⽂叫做模型,对应数据库;
V : 表⽰View,翻译为中⽂叫做视图,对应前端的页⾯,⽐如jsp
C : 表⽰ Controller ,翻译是控制层,对应servlet的请求映射;
Spring MVC执⾏原理
终于到重点了,其实我在开头的时候已经答对了⼀半了,只是呢,少了⼀个叫做的东东,还有⼀些其他的细节,看下⾯这张图就明⽩了
Spring mvc 执⾏流程
1. 服务器收到请求后,servlet 会将所有的请求都交给前端控制器(DispatcherServlet)处理;
2. 前端控制器(DispatcherServlet)先调⽤HandlerMapping(处理器映射器),handlerMapping 根据请求url查控制器
(handler),返回⼀个 HandlerExecutionChain(处理器执⾏链) ,HandlerExecutionChain中除了控制器的信息之外,还有的信息;
3. 接着将HandlerExecutionChain(处理器执⾏链)返回给 前端控制器(DispatcherServlet),调⽤适配器之前会先执⾏前置
的代码,接着 DispatcherServlet 调⽤ HandlerAdapter(适配器)执⾏controller 层的代码内容,也就是带@Controller注解的类⾥⾯的代码,返回⼀个ModelAndView (逻辑视图);注意,这⾥的逻辑视图还不是真正的jsp页⾯;因为它还没经过渲染;再⼀次执⾏后置;
4. 到这⼀步,DispatcherServlet就会调⽤ViewResolver(视图解析器)来解析ModelAndView 对象,得到⼀个View(视图),这个
视图就是已经渲染好了的jsp页⾯了,然后把页⾯返回给前端之前在执⾏⼀次;
在mvc⾥⾯,最重要的⽆⾮就这⼏样 DispatcherServlet 、 HandlerMapping 、 HandlerExecutionChain 、 HandlerInterceptor、 HandlerAdapter、 ModelAndView、ViewResolver 、 View;别着急,我们⼀个个讲解它们的作⽤是什么;
DispatcherServlet
DispatcherServlet 的中⽂叫做前端控制器 ,也就叫中央调度器,⽤户发送的所有请求都会经过这个接⼝,由Servlet调⽤,是⽤来拦截所有请求的url的⼊⼝,并根据url地址分发到不同的controller ;在l中配置后即可使⽤
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="/2001/XMLSchema-instance" xmlns="java.sun/xml/ns/javaee" xsi:schemaLocation="java.sun/xml/ns/j <display-name>SpringMVC_01</display-name>
<!-- 注册中央调度器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- tomcat启动时⾃动创建servlet,数字越⼩优先级越⾼(>0) -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 拦截所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
HandlerMapping
HandlerMapping的作⽤就是解析请求链接,然后根据请求链接到执⾏这个请求的类(HandlerMapping所说的handler,也就是我
们写的Controller或是Action),也叫做控制器映射器,如果未匹配到控制器,则返回404错误;HandlerExecutionChain
HandlerExecutionChain 是Handler的执⾏链,我叫他控制器执⾏链,包含控制器对象handler、 interceptor。所以HandlerExecutionChain 提供了getHandler、getInterceptors⽅法,配置⽂件中配置的interceptor都会加⼊到
HandlerExecutionChain;需要注意的是,的列表⾥⾯除了我们配置的之外,还有⼀个springmvc⾃⼰维护的;HandlerInterceptor ()
控制器的,⼀般都是作为扩展使⽤,⼀共有三个⽅法:
preHandle() :在业务处理器处理请求之前被调⽤。预处理,可以进⾏编码、安全控制、权限校验等处理;preHandle有⼀个boolen 类型的返回值,返回 true 表⽰正常执⾏,返回 false 表⽰拦截请求.如果返回 false ,postHandle() 和 afterCompletion() ⽅法都不会执⾏;
postHandle() :在业务处理器处理请求执⾏完成后调⽤,⽣成视图之前执⾏。后处理(调⽤了Service并返回ModelAndView,但未进⾏页⾯渲染),有机会修改ModelAndView ;当controller层抛出异常后不会执⾏postHandle⽅法,
afterCompletion() :在DispatcherServlet完全处理完请求后被调⽤,可⽤于清理资源等。返回处理(已经渲染了页⾯);当
controller层抛出异常后依然会执⾏afterCompletion⽅法
代码⽰例
package com.ller.Interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* springmvc
*
*/
@Component
public class MvcInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("处理器处理请求之前被调⽤");
// 返回true正常执⾏,返回false 表⽰拦截请求,
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // preHandle⽅法返回false则不会执⾏到这⾥
System.out.println("处理器处理请求执⾏完成后调⽤");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// preHandle⽅法返回false则不会执⾏到这⾥
System.out.println("DispatcherServlet完全处理完请求后被调⽤");
}
}
打印结果
AOP切⾯编程 @Aspect
Spring AOP⾯向切⾯编程,可以⽤来配置事务、做⽇志、权限验证、在⽤户请求时做⼀些处理等等。⽤@Aspect做⼀个切⾯,就可以直接实现。切⾯内有以下⼏个注解:
1. @Aspect:定义切⾯类,将被标识的类作为⼀个切⾯bean
2. @Pointcut:切⼊点,这⾥进⾏配置切⼊的范围,如果你只想在controller层进⾏切⼊,那就这样配置 :
@Pointcut("execution(public * com.ller.*.*(..))")
3. @Around:环绕增强
4. @Before:前置增强
5. @AfterReturning:后置增强—⽅法正常退出时执⾏
6. @AfterThrowing:后置增强—⽅法异常执⾏
7. @After:后置增强—增强anyway
如果是springboot项⽬,需要在启动类上⾯加上 @EnableAspectJAutoProxy(proxyTargetClass = true) 注解,这个注解表⽰开启aop⾃动代理,proxyTargetClass=true 表⽰优先使⽤jdk动态代理, 如果是接⼝的⽅式则使⽤jdk动态代理,如果是在类上⾯则使⽤cglib 动态代理实现,另外博主也测试过,好像不加@EnableAspectJAutoProxy 注解也能实现aop⾃动代理,但为了保险起见,还是加上吧;
//exclude 表⽰排除注⼊
@SpringBootApplication //(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
//开启事务管理
@EnableTransactionManagement
// 开启切⾯,proxyTargetClass=true表⽰优先使⽤jdk动态代理,如果没有接⼝,则使⽤cglib动态代理
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class App extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
接下来定义⼀个切⾯类 AspectClass.java ,在类上加⼊ @Aspect 注解
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论