SpringMVC原理

1 什么是Spring MVC ?简单介绍下你对springMVC的理解?

Spring MVC是一个基于MVC架构的用来简化web应用程序开发的应用开发框架,它是Spring的一个模块,无需中间整合层来整合 ,它和Struts2一样都属于表现层的框架。

在web模型中,MVC是一种很流行的框架,通过把Model,View,Controller分离,把较为复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。

mvc详情

2 SpringMVC的流程?

(1)用户发送请求至前端控制器DispatcherServlet;
(2)DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handler;
(3)处理器映射器根据请求url找到具体的处理器Handler,生成处理器对象及处理器拦截器(如果有则生成),一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器,请求执行Handler;
(5)HandlerAdapter 经过适配调用 具体处理器进行处理业务逻辑;
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。

前端控制器 DispatcherServlet:接收请求、响应结果,相当于转发器,有了DispatcherServlet就减少了其它组件之间的耦合度。
处理器映射器 HandlerMapping:根据请求的URL来查找Handler
处理器适配器HandlerAdapter:负责执行Handler
处理器 Handler:处理器,需要程序员开发
视图解析器ViewResolver:进行视图的解析,根据视图逻辑名将ModelAndView解析成真正的视图(view)
视图View:View是一个接口, 它的实现类支持不同的视图类型,如jsp,freemarker,pdf等等

详情

转发和重定向

(1)转发:在返回值前面forward

(2)重定向:在返回值前面加redirect:

  • 转发属于一次请求,重定向则是二次请求
  • 转发的地址栏不会改变,重定向的地址栏改变
  • 转发写跳转路径时不需要写工程名,重定向则需要加上项目工程名(eg:request.getContextPath + “/demo”)
  • 转发路径只能写项目内部资源的地址(eg:www.baidu.com不允许!),而重定向内外资源不限制
  • request域存取的值在转发(属于一次请求)中有效,重定向(二次请求)中无效

Springmvc的优点:

(1)可以支持各种视图技术,而不仅仅局限于JSP;

(2)与Spring框架集成(如IoC容器、AOP等);

(3)清晰的角色分配:前端控制器(dispatcherServlet) ,处理器映射器(handlerMapping),处理器适配器(HandlerAdapter),视图解析器(ViewResolver)。

(4) 支持各种请求资源的映射策略。

SpringMVC常用的注解有哪些?

@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。

@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。

@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。

SpingMvc中的控制器的注解一般用哪个?有没有别的注解可以替代?

一般用@Controller注解,也可以使用@RestController@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。

Spring MVC的异常处理 ?

可以将异常抛给Spring框架,由Spring框架来处理;我们只需要配置简单的异常处理器,在异常处理器中添视图页面即可。

SpringMvc的控制器是不是单例模式?如果是,有什么问题?怎么解决?

是单例模式,在多线程访问的时候有线程安全问题,解决方案是在控制器里面不能写可变状态量,如果需要使用这些可变状态,可以使用ThreadLocal机制解决,为每个线程单独生成一份变量副本,独立操作,互不影响。

ThreadLocal原理

通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢? JDK 中提供的ThreadLocal类正是为了解决这样的问题。 ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。

如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是ThreadLocal变量名的由来。他们可以使用get()set() 方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题。

Thread类源代码入手。

public class Thread implements Runnable {
   
 ......
//与此线程有关的ThreadLocal值。由ThreadLocal类维护
ThreadLocal.ThreadLocalMap threadLocals = null;

//与此线程有关的InheritableThreadLocal值。由InheritableThreadLocal类维护
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
 ......
}

从上面Thread类 源代码可以看出Thread类中有一个 threadLocals和 一个inheritableThreadLocals变量,它们都是ThreadLocalMap类型的变量,我们可以把 ThreadLocalMap理解为ThreadLocal类实现的定制化的HashMap。默认情况下这两个变量都是 null,只有当前线程调用 ThreadLocal类的 setget方法时才创建它们,实际上调用这两个方法的时候,我们调用的是ThreadLocalMap类对应的 get()set()方法。

ThreadLocal类的set()方法

    public void set(T value) {
   
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    ThreadLocalMap getMap(Thread t) {
   
        return t.threadLocals;
    }

通过上面这些内容,我们足以通过猜测得出结论:最终的变量是放在了当前线程的 ThreadLocalMap中,并不是存在ThreadLocal 上,ThreadLocal可以理解为只是ThreadLocalMap的封装,传递了变量值。 ThrealLocal类中可以通过Thread.currentThread()获取到当前线程对象后,直接通过getMap(Thread t)可以访问到该线程的ThreadLocalMap对象。

每个Thread中都具备一个ThreadLocalMap,而ThreadLocalMap可以存储以ThreadLocal为 key ,Object对象为 value 的键值对。

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
   
 ......
}

比如我们在同一个线程中声明了两个ThreadLocal对象的话,会使用 Thread内部都是使用仅有那个ThreadLocalMap存放数据的,ThreadLocalMap的 key 就是ThreadLocal对象,value 就是ThreadLocal 对象调用set方法设置的值。

ThreadLocalMap是ThreadLocal的静态内部类。

SpringMvc中函数的返回值是什么?

返回值可以有很多类型,有String,ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
3
分享

创作者周榜

更多
牛客网
牛客企业服务