SpringMVC总结

本文详细介绍了SpringMVC的工作流程,包括前端控制器DispatcherServlet、处理器映射器HandlerMapping、处理器适配器HandlerAdapter、后端控制器Handler、视图解析器ViewResolver以及视图View的角色。此外,还探讨了SpringMVC与AJAX的交互,以及SpringMVC控制器的单例模式下线程安全问题和解决方案。文章最后比较了SpringMVC与Struts2的区别,并解答了关于控制器注解、请求映射、事务管理等方面的问题。
摘要由CSDN通过智能技术生成

MVC : Model      View       Controller

SpringMVC控制器层的框架,主要包含以下组件:

(1)前端控制器 DispatcherServlet(核心入口):配置在web.xml文件中的,拦截匹配的请求,把拦截下来的请求,

            依据相应的 规则分发到目标Controller来处理,是配置spring MVC的第一步

           作用:接收请求、响应结果 相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。

(2)处理器映射器HandlerMapping(不需要程序员开发)

          作用:根据请求的URL来查找Handler

(3)处理器适配器HandlerAdapter

        注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。

(4)后端控制器Handler(需要程序员开发)

(5)视图解析器 ViewResolver(不需要程序员开发)

         作用:进行视图的解析 根据视图逻辑名解析成真正的视图(view)

(6)视图View(需要程序员开发jsp)

          View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)

 

SpringMVC的流程:

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

 

 

 

SpringMvc怎么和AJAX相互调用的:

通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 :

(1)加入Jackson.jar

          

(2)在配置文件中配置json的映射

(3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解

         (通过使用@ResponseBody注解, 可以自动将控制器方法的返回值转换成json字符串。)

 

1、springMVC和struts2的区别有哪些?

       (1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器                                        (StrutsPrepareAndExecuteFilter)。

       (2)springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),

               struts2是   基于类开发,传递参数是通过类的属性,只能设计为多例

       (3)Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方                      法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp                    视图解析器默认使用jstl。
 

2、SpringMvc的核心入口类是什么,Struts1,Struts2的分别是什么:

        答:SpringMvc的是DispatchServlet,

               Struts1的是ActionServlet,

               Struts2的是StrutsPrepareAndExecuteFilter。

 

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

       答:Java里有个API叫做ThreadLocal,spring单例模式下用它来切换不同线程之间的参数。用ThreadLocal是为了保证线程安全,实际上ThreadLoacal的key就是当前线程的Thread实例。单例模式下,spring把每个线程可能存在线程安全问题的参数值放进了ThreadLocal。这样虽然是一个实例在操作,但是不同线程下的数据互相之间都是隔离的,因为运行时创建和销毁的bean大大减少了,所以大多数场景下这种方式对内存资源的消耗较少,而且并发越高优势越明显。
单利模式因为大大节省了实例的创建和销毁,有利于提高性能,而ThreadLocal用来保证线程安全性
单例模式是spring推荐的配置,它在高并发下能极大的节省资源,提高服务抗压能力。spring IOC的bean管理器是“绝对的线程安全”。

最佳实践:
1、不要在controller中定义成员变量
2、万一必须要定义一个非静态成员变量时候,则通过注解
@Scope("prototype"),将其设置为多例模式

springmvc成员方法也是共享的,为什么就不会出现问题呢?
java 里,每个线程都有自己独享的空间,也就是栈内存。线程在调用方法的时候,会创建一个栈帧。也就是说调用一个方法的时候,也就是一个栈帧的入栈过程,该方法执行完毕,栈帧也就出栈了。
换句话讲,成员方法对于每个线程事实上是私有的,而不是你表面看上去的那样是 "共享" 的。

那么为什么springmvc成员变量会出问题呢?
如你所知道的,每个新建对象都存放在堆中,每个持有该对象引用的线程,都可以访问到它(只要你有那个权限)。
这也就是说,成员变量对于每个线程,事实上是共享的

栈、堆、方法区
JAVA的JVM的内存可分为5个区:

堆(heap)、栈(stack)和方法区(method)、程序计数器、本地方法栈()


堆区:

提供所有类实例和数组对象存储区域

jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身


栈区:

每个线程包含一个栈区,栈中只保存基本数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中

每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。


方法区:

又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量

方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

运行时常量池都分配在 Java 虚拟机的方法区之中。
 

 程序计数器:

程序计数器 在 运行时数据区 只占据非常小的内存空间,它用来存储下一个即将执行的字节码指令的地址

本地方法栈:

(本地方法栈)与Java Stacks(Java 栈)非常类似,它用于存储调用本地方法(C/C++)所涉及到的局部变量表、操作栈等信息。

4、SpringMvc中的控制器的注解一般用那个,有没有别的注解可以替代?

       答:一般用@Conntroller注解,表示是控制层,不能用用别的注解代替

 

5、 @RequestMapping注解用在类上面有什么作用?

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

 

6、怎么样把某个请求映射到特定的方法上面

        答:直接在方法上面加上注解@RequestMapping,并且在这个注解里面写上要拦截的路径。

 

7、如果在拦截请求中,我想拦截get方式提交的方法,怎么配置?

         答:可以在@RequestMapping注解里面加上method=RequestMethod.GET

 

8、怎么样在方法里面得到Request,或者Session?

       答:直接在方法的形参中声明request,SpringMvc就自动把request对象传入。

 

18、如果想在拦截的方法里面得到从前台传入的参数,怎么得到?

        答:直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。

 

9、如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象?

       答:直接在方法中声明这个对象,SpringMvc就自动会把属性赋值到这个对象里面。

 

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

       答:返回值可以有很多类型,String, ModelAndView,但一般用String比较好。

 

11、SpringMvc用什么对象从后台向前台传递数据的?

      答:向request作用域存数据,通过ModelMap对象,可以在这个对象里面用put方法,把对象加到里面,前台就可以通过el表达式拿到。

             向session作用域存入数据

12、SpringMvc中有个把视图和数据都合并的一起的,叫什么?

        答:叫ModelAndView。

 

13、怎么样把ModelMap里面的数据放入Session里面?

        答:可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key

@Controller

@SessionAttributes({“name”})            // 将model中为name命名属性存入session作用域(里的key

Public class xxxController{

Public String test1(Model model){

      Model.addAttribute(String name,Object value);

}

// 移除

Public String test2(SessionStatus sessionStatus){

        sessionStatus.setComplete();// 移除通过model方式存入session作用域的命名属性

}

}

14、当一个方法向AJAX返回特殊对象,譬如Object,List等,需要做什么处理?

        答:要加上@ResponseBody注解。

              (通过使用@ResponseBody注解, 可以自动将控制器方法的返回值转换成json字符串。)

15、spring 事务管理有几种方式?有什么区别?

               Spring支持如下两种方式的事务管理:

               编程式事务管理:这意味着你可以通过编程的方式管理事务,这种方式带来了很大的灵活性,但很难维护。

               声明式事务管理:这种方式意味着你可以将事务管理和业务代码分离。你只需要通过注解或者XML配置管理事务。

                                           一般选择声明式事务管理,因为这种方式和应用程序的关联较少。
 

16、在SpringAOP中,在同一个service中,A方法有事务,B方法没事务,A方法调用B方法,会不会破坏A方法的事务,为什么?

 1:内部调用时,被调用方法的事务声明将不起作用 2:换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中 3:再换句话说,Spring的事务传播策略在内部方法调用时将不起作用。不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。 4:不仅仅是事务通知,所有你自己利用Spring实现的AOP通知,都会受到同样限制。。。。

           我们知道Spring中事务管理是使用AOP代理技术实现的,目标对象自身并没有事务管理功能的,而是通过代理对象
           动态增强功能对事务进行增强的
。因此当我们在同一个service类中通过一个方法调用另一个方法时,是通过
           标对象this对象
调用的,目标对象自身没有事务管理功能,因此事务不能生效。

解决方案:
1.使用xml配置方式暴漏代理对象,然后在service中通过代理对象AopContext.currentProxy()去调用方法。
xml配置
<aop:aspectj-autoproxy expose-proxy="true"/>
1
service调用
@Service
public class HelloWorldServiceImpl implements HelloWorldService {
    @Autowired
    private BlogRepository blogRepository;

    @Override
    public void a(BlogEntity blogEntity) throws Exception {
        ((HelloWorldService) AopContext.currentProxy()).b(blogEntity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void b(BlogEntity blogEntity) throws Exception {
        blogRepository.save(blogEntity);
        throw new Exception("错误");
    }
}

2.在java配置类上添加注解@EnableAspectJAutoProxy(exposeProxy = true)方式暴漏代理对象,然后在service中通过代理对象AopContext.currentProxy()去调用方法。
java配置类
/**
 * @Author: PanChao
 * @Description:
 * @Date: Created in 13:14 2018/9/27
 */
@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
public class AppConfig {
}

service调用
@Service
public class HelloWorldServiceImpl implements HelloWorldService {
    @Autowired
    private BlogRepository blogRepository;

    @Override
    public void a(BlogEntity blogEntity) throws Exception {
        ((HelloWorldService) AopContext.currentProxy()).b(blogEntity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void b(BlogEntity blogEntity) throws Exception {
        blogRepository.save(blogEntity);
        throw new Exception("错误");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值