文章目录
- Q1、Spring事件监听的核心机制是什么?
- Q2、Spring框架中都用到了哪些设计模式?
- Q3、Spring是如何整合MyBatis来管理Mapper接口的?
- Q4、说说SpringMVC如何解决GET和POST的乱码问题的?
- Q5、Spring MVC的控制器是不是单例模式,如果是,有什么问题?如何解决?
- Q7、描述SpringMVC的工作流程?
- Q8、Spring MVC中处理AJAX请求的原理?
- Q9、Spring搭配SpringMVC为什么需要父子容器?
- Q10、是否可以把Spring MVC的所有Bean都交给Spring容器来管理?
- Q11、是否可以把Spring的Bean都交给Spring MVC来管理?
- Q12、如何实现零配置的Spring MVC?原理是什么?
- Q13、SpringMVC的拦截器和过滤器有什么区别?
Q1、Spring事件监听的核心机制是什么?
前置知识补充:
关于事件监听,有三大部分:
- 事件
- 监听器
- 发布器(Spring提供)
用法demo,发布事件:(默认同步,发布完事件后,等待监听器执行后,再往下继续执行。异步事件发布是多线程。)
监听器:
以上这种模式主要是为了实现业务的解耦,提高可扩展性和可维护性。当然这种需求在微服务中用MQ更多一些。
答案:
Spring事件监听的核心机制是观察者模式。Spring事件监听由三部分组成:
-
事件(ApplicationEvent) :可以自己创建,Spring内部也创建了一些事件
-
监听器(ApplicationListener) :对应于观察者模式中的
观察者
。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑 -
事件发布器 (ApplicationEventMulticaster) :对应于观察者模式中的
被观察者
/主题,负责通知观察者 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器
Q2、Spring框架中都用到了哪些设计模式?
答案:
- 1.简单工厂:BeanFactory
- 2.工厂方法:FactoryBean
- 3.单例模式:Bean实例
- 4.适配器模式:SpringMVC中的HandlerAdatper
- 5.装饰器模式:BeanWrapper
- 6.代理模式:AOP底层
- 7.观察者模式:spring的事件监听
- 8.策略模式:exdludeFilters、indludeFilters
- 9.横版方法模式:Spring几乎所有的外接扩展都采用这种模式
- 10.责任链模式:Aop的方法调用
Q3、Spring是如何整合MyBatis来管理Mapper接口的?
答案:
- 1.首先MyBatis的
Mapper接口
(没有实现类)核心是JDK动态代理 - 2.Spring会排除接口(和抽象类),无法注册到IOC容器中
- 3.MyBatis 实现了
BeanDefinitionRegistryPostProcessor
,可以动态注册BeanDefinition - 4.需要
自定义扫描器
(继承Spring内部扫描器ClassPathBeanDefinitionScanner) 重写排除接口的方法 isCandidateComponent) - 5.但是接口虽然注册成了BeanDefinition,但是无法实例化Bean( 因为接口不能new对象)
- 6.需要将BeanDefinition的BeanClass
替换成JDK动态代理的实例
(偷天换日) - 7.Mybatis 通过FactoryBean的工厂方法设计模式可以自由控制Bean的实例化过程,可以在getObject方法中创建JDK动态代理
Q4、说说SpringMVC如何解决GET和POST的乱码问题的?
答案:
在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8:
对于GET请求中文参数乱码,有两种思路:一是修改tomcat配置文件添加编码与工程编码一致:
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8880" protocol="HTTP/1.1" redirectPort="8443"/>
另一种是对参数进行重新编码:
String userName = new String(request.getParamter.getBytes("ISO8859-1"),"utf-8");
Q5、Spring MVC的控制器是不是单例模式,如果是,有什么问题?如何解决?
答案:
默认是单例模式,此时如果在类里声明成员变量,且两个线程对这个成员变量进行读写操作,就会有线程安全的问题。解决思路有:
- 成员变量声明在方法中(局部变量)
- 使用ThreadLocal绑定在本地线程中
- 加同步锁(影响吞吐,并行变串行)
Q7、描述SpringMVC的工作流程?
等价问题:
描述下DispatchServlet的工作流程?
答案:
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle
- 处理器映射器根据请求ur找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成),一并返回给DispatcherServlet
- DispatcherServlet 调用 HandlerAdapter处理器适配器
- HandlerAdapter 经过适配调用具体处理器(Handler,也叫后端控制器)
- Handler执行完成返回ModelAndView
- HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析
- ViewResolver解析后返回具体View
- DispatcherServlet对View进行渲染视图 (即将模型数据填充至视图中)
- DispatcherServlet响应用户
Q8、Spring MVC中处理AJAX请求的原理?
答案:
- 加入json和Java对象互转的依赖Jackson.jar(也可用其他的jar)
- 在配置我呢见中配置json的消息转换器(Jackson不需要该配置HttpMessageConverter)
<!--它就帮我们配置了默认json映射-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
- SpringMVC对数据Message的处理操作提供了个接门
HttpMessageConverter
,用来对参数值和返回值的转换处理,在请求和返回过程中可以进行转换json和Java对象
接上个问题,加入消息转换器:
Q9、Spring搭配SpringMVC为什么需要父子容器?
答案:
就功能性来说不用子父容器也可以完成 (参考:springBoot就没用子父容器),使用父子容器,原因有:
- 父子容器的主要作用应该是划分框架边界,有点单一职责的味道。service、dao层的Bean一般使用spring框架来管理,controller层的Bean则交给springmvc管理
- 规范整体架构,(父子容器有个特性,子容器可以访问父容器中的Bean,父容器不能访问子容器中的Bean)使父容器service中无法访问子容器controller、子容器controller可以访问父容器service(Controller中注入Service的Bean,Service不能注入Controller中的Bean)
- 方便子容器的切换,如果现在我们想把web层从spring mvc替换成struts,那么只需要将spring-mvc.xml替换成struts的配置文件struts.xm1即可,而spring-core.xml不需要改变
Q10、是否可以把Spring MVC的所有Bean都交给Spring容器来管理?
答案:
不可以,这样会导致我们请求接口的时候产生404。 如果所有的Bean都交给父容器,SpringMVC在初始化HandlerMethods的时候(initHandlerMethods) ,无法根据Controller的handler方法注册HandlerMethod,并没有去查找父容器的bean,也就无法根据请求URI 获取到 HandlerMethod来进行匹配。
Q11、是否可以把Spring的Bean都交给Spring MVC来管理?
答案:
可以,因为父容器的体现无非是为了获取子容器不包含的bean,如果全部包含在子容器完全用不到父容器了,所以是可以全部放在springmvc子容器来管理的。
虽然可以这么做不过一般应该是不推荐这么去做的,一般人也不会这么干的。如果你的项目里有用到事务、或者aop记得也需要把这部分配置需要放所以如到Spring-mvc子容器的配置文件来,不然一部分内容在子容器和一部分内容在父容器,可能就会导致你的事务或者AOP不生效。所以如果aop或事务不生效也有可能是通过父容器(spring)去增强子容器(Springmvc),也就无法增强。
Q12、如何实现零配置的Spring MVC?原理是什么?
答案:
第一种方式就是使用注解代替web.xml文件,相关注解:
- @WebServlet
- @WebListener
- @WebFilter
第二种是基于SPI来实现:
省略web.xml
- a. servlet3.0之后规范中提供了
SPI扩展
:META-INF/services/iavax.servlet.ServletContainerlnitializer - b.SpringMVC通过实现ServletContainerlnitializer接口
- c.动态注册ContextLoaderListener 和DispatcherServlet并创建子父容器(Application)
省略spring.xml和spring-mvc.xml(只是springmvc方式,springboot在自动配置类完成) 配置类--xml
- a.实现一个继承AbstractAnnotationConfigDispatcherServletlnitializer的类
- b. 该类就实现了ServletContainerlnitializer,它会创建ContextLoaderListener 和DispatcherServlet
- c.还会创建父子容器,创建容器时传入父子容器配置类则可以替代spring.xm和spring-mvc.xml
Q13、SpringMVC的拦截器和过滤器有什么区别?
答案:
- 拦截器不依赖于servlet容器,过滤器依赖与servlet容器。
- 拦截器只能对action请求(DispatcherServlet 映射的请求)起作用,而过滤器则可以对几乎所有的请求起作用
- 拦截器可以访问容器中的Bean(DI),而过滤器不能访问(基于spring注册的过滤器也可以访问容器中的bean)。
========
听吐了这节,对Spring MVC了解太少,后面再复习吧。。。。。