Spring

1、使用 Spring 框架的好处是什么?

  1. 轻量:Spring 是轻量的,基本的版本大约 2MB。
    2. 控制反转:Spring 通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
    3. 面向切面的编程(AOP):Spring 支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
    4. 容器:Spring 包含并管理应用中对象的生命周期和配置。
    5. MVC框架:Spring 的 Web 框架是个精心设计的框架,是 Web 框架的一个很好的替代品。
    6. 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
    7. 异常处理:Spring 提供方便的 API 把具体技术相关的异常(比如由 JDBC,Hibernate or JDO 抛出的)转化为一致的 unchecked 异常。

    2、解释下什么是 AOP?

    AOP(Aspect-Oriented Programming,面向方面编程),可以说是 OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP 引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP 则显得无能为力。也就是说,OOP 允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如:安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在 OOP 设计中,它导致了大量代码的重复,而不利于各个模块的重用。
    而 AOP 技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP 代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
    使用“横切”技术,AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,它们经常发生在核心关注点的多处,而各处都基本相似。比如:权限认证、日志、事务处理。AOP 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

    3、AOP 的代理有哪几种方式?

    AOP 思想的实现一般都是基于代理模式 ,在 Java 中一般采用 JDK 动态代理模式,但是我们都知道,JDK 动态代理模式只能代理接口而不能代理类。因此,Spring AOP 会按照下面两种情况进行切换,因为 Spring AOP 同时支持 CGLIB、ASPECTJ、JDK 动态代理。
    1. 如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
    2. 如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类。不过这个选择过程对开发者完全透明、开发者也无需关心。

    4、怎么实现 JDK 动态代理?

    JDK 动态代理最核心的一个接口和方法如下所示:
  • 1. java.lang.reflect 包中的 InvocationHandler 接口:



public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
对于被代理的类的操作都会由该接口中的 invoke 方法实现,其中的参数的含义分别是:
1. proxy:被代理的类的实例;

  1. method:调用被代理的类的方法;
  2. args:该方法需要的参数。
    使用方法首先是需要实现该接口,并且我们可以在 invoke 方法中调用被代理类的方法并获得返回值,自然也可以在调用该方法的前后去做一些额外的事情,从而实现动态代理。
  • 2. java.lang.reflect 包中的 Proxy 类中的 newProxyInstance 方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
其中的参数含义如下:
1. loader:被代理的类的类加载器;
2. interfaces:被代理类的接口数组;
3. invocationHandler:调用处理器类的对象实例。
该方法会返回一个被修改过的类的实例,从而可以自由的调用该实例的方法。

5、AOP 的基本概念:切面、连接点、切入点等?

  1. 切面(Aspect):官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。
    2. 连接点(Joinpoint):程序执行过程中的某一行为。
    3. 通知(Advice):“切面”对于某个“连接点”所产生的动作。
    4. 切入点(Pointcut):匹配连接点的断言,在 AOP 中通知和一个切入点表达式关联。
    5. 目标对象(Target Object):被一个或者多个切面所通知的对象。
    6. AOP 代理(AOP Proxy):在 Spring AOP 中有两种代理方式,JDK 动态代理和 CGLIB 代理。

    6、通知类型(Advice)型(Advice)有哪些?

  2. 前置通知(Before advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext 中在 里面使用 元素进行声明;
    2. 后置通知(After advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext 中在 里面使用 元素进行声明。
    3. 返回后通知(After return advice :在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext 中在 里面使用 <> 元素进行声明。
    4. 环绕通知(Around advice):包围一个连接点的通知,类似 Web 中 Servlet规范中的 Filter 的 doFilter 方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext 中在 里面使用 元素进行声明。
    5. 抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。ApplicationContext 中在 里面使用 元素进行声明。
    7、谈谈你对 IOC 的理解?
    IOC 是 Inversion of Control 的缩写,多数书籍翻译成“控制反转”。简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。IOC 理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦。如下图:
    Java框架 - 图1
    由于引进了中间位置的“第三方”,也就是 IOC 容器,使得 A、B、C、D 这 4 个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC 容器,所以,IOC 容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把 IOC 容器比喻成“粘合剂”的由来。 
    把上图中间的 IOC 容器拿掉,然后再来看看这套系统:
    Java框架 - 图2
    现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D 这 4 个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现 A 的时候,根本无须再去考虑 B、C 和 D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现 IOC 容器,对于系统开发而言,这将是一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系!
    我们再来看看,控制反转(IOC)到底为什么要起这么个名字?我们来对比一下:
    软件系统在没有引入 IOC 容器之前,对象 A 依赖于对象 B,那么对象 A 在初始化或者运行到某一点的时候,自己必须主动去创建对象 B 或者使用已经创建的对象 B。无论是创建还是使用对象 B,控制权都在自己手上。
    软件系统在引入 IOC 容器之后,这种情形就完全改变了,由于 IOC 容器的加入,对象 A 与对象 B 之间失去了直接联系,所以,当对象 A 运行到需要对象 B 的时候,IOC 容器会主动创建一个对象 B 注入到对象 A 需要的地方。
    通过前后的对比,我们不难看出来:对象 A 获得依赖对象 B 的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。

    8、Bean 的生命周期?

    在传统的 Java 应用中,bean 的生命周期很简单,使用 Java 关键字 new 进行 Bean 的实例化,然后该 Bean 就能够使用了。一旦 Bean 不再被使用,则由 Java 自动进行垃圾回收。
    相比之下,Spring 管理 Bean 的生命周期就复杂多了,正确理解 Bean 的生命周期非常重要,因为 Spring 对 Bean 的管理可扩展性非常强,下面展示了一个 Bean 的构造过程:
    Java框架 - 图3
    1. Spring 启动,查找并加载需要被 Spring 管理的 Bean,进行 Bean 的实例化;
    2. Bean 实例化后,对 Bean 的引入和值注入到 Bean 的属性中;
    3. 如果 Bean 实现了 BeanNameAware 接口的话,Spring 将 Bean 的 Id 传递给 setBeanName() 方法;
    4. 如果 Bean 实现了 BeanFactoryAware 接口的话,Spring 将调用 setBeanFactory() 方法,将 BeanFactory 容器实例传入;
    5. 如果 Bean 实现了 ApplicationContextAware 接口的话,Spring 将调用 Bean 的 setApplicationContext() 方法,将 Bean 所在应用上下文引用传入进来;
    6. 如果 Bean 实现了 BeanPostProcessor 接口,Spring 就将调用它们的 postProcessBeforeInitialization() 方法;
    7. 如果 Bean 实现了 InitializingBean 接口,Spring 将调用它们的 afterPropertiesSet() 方法。类似地,如果 Bean 使用 init-method 声明了初始化方法,该方法也会被调用;
    8. 如果 Bean 实现了 BeanPostProcessor 接口,Spring 就将调用它们的 postProcessAfterInitialization() 方法;
    9. 此时,Bean 已经准备就绪,可以被应用程序使用了。它们将一直驻留在应用上下文中,直到应用上下文被销毁;
    10. 如果 Bean 实现了 DisposableBean 接口,Spring 将调用它的 destory() 接口方法,同样,如果 Bean 使用了 destory-method 声明销毁方法,该方法也会被调用。

    9、Bean 的作用域?

  3. singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的;
    2. prototype : 每次请求都会创建一个新的 bean 实例;
    3. request:每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效;
    4. session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效;
    5. global-session:全局 session 作用域,仅仅在基于 portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

    10、Spring 中的单例 Bean 的线程安全问题了解吗?

    大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例 bean 存在线程问题,主要是因为:当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。常见的有两种解决办法:
    1. 在 Bean 对象中尽量避免定义可变的成员变量(不太现实)。
    2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

    11、谈谈你对 Spring 中的事物的理解?

    事务是逻辑上的一组操作,要么都执行,要么都不执行。
  • 事务特性

原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
一致性:执行事务前后,数据保持一致;
隔离性:并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的;
持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

  • Spring 事务管理接口
  1. PlatformTransactionManager:(平台)事务管理器;
    2. TransactionDefinition:事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则);
    3. TransactionStatus:事务运行状态;
    所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作”。

    12、Spring 中的事务隔离级别?

    TransactionDefinition 接口中定义了五个表示隔离级别的常量:
    TransactionDefinition.ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别;
    TransactionDefinition.ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读;
    TransactionDefinition.ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生;
    TransactionDefinition.ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生;
    TransactionDefinition.ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

    13、Spring 中的事物传播行为?

    事务传播行为是为了解决业务层方法之间互相调用的事务问题。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。在 TransactionDefinition 定义中包括了如下几个表示传播行为的常量:
  • 支持当前事务的情况:

TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务;
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行;
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

  • 不支持当前事务的情况:

TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起;
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

  • 其他情况:

TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 TransactionDefinition.PROPAGATION_REQUIRED。

14、Spring 常用的注入方式有哪些?

  1. 构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
    2. Setter 方法注入:Setter 方法注入是容器通过调用无参构造器或无参 static 工厂方法实例化 bean 之后,调用该 bean 的 Setter 方法,即实现了基于 Setter 的依赖注入。
    3. 基于注解的注入:最好的解决方案是用构造器参数实现强制依赖,Setter 方法实现可选依赖。

    15、Spring 框架中用到了哪些设计模式?

  2. 工厂设计模式 : Spring 使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象;
    2. 代理设计模式 : Spring AOP 功能的实现;
    3. 单例设计模式 : Spring 中的 Bean 默认都是单例的;
    4. 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式;
    5. 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源;
    6. 观察者模式:Spring 事件驱动模型就是观察者模式很经典的一个应用;
    7. 适配器模式:Spring AOP 的增强或通知(Advice)使用到了适配器模式、SpringMVC 中也是用到了适配器模式适配 Controller。

    16、ApplicationContext 通常的实现有哪些?

  3. FileSystemXmlApplicationContext:此容器从一个 XML 文件中加载beans 的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
    2. ClassPathXmlApplicationContext:此容器也从一个 XML 文件中加载beans 的定义,这里,你需要正确设置 classpath 因为这个容器将在 classpath 里找 bean 配置。
    3. WebXmlApplicationContext:此容器加载一个 XML 文件,此文件定义了一个 Web 应用的所有 bean。

SpringMVC

1、谈谈你对 MVC 模式的理解?

MVC 是 Model — View — Controler 的简称,它是一种架构模式,它分离了表现与交互。它被分为三个核心部件:模型、视图、控制器。
链接

Model(模型):是程序的主体部分,主要包含业务数据和业务逻辑。在模型层,还会涉及到用户发布的服务,在服务中会根据不同的业务需求,更新业务模型中的数据。
View(视图):是程序呈现给用户的部分,是用户和程序交互的接口,用户会根据具体的业务需求,在 View 视图层输入自己特定的业务数据,并通过界面的事件交互,将对应的输入参数提交给后台控制器进行处理。
Controller(控制器):Controller 是用来处理用户输入数据,以及更新业务模型的部分。控制器中接收了用户与界面交互时传递过来的数据,并根据数据业务逻辑来执行服务的调用和更新业务模型的数据和状态。

2、SpringMVC 的工作原理/执行流程?

简单来说:客户端发送请求-> 前端控制器 DispatcherServlet 接受客户端请求 -> 找到处理器映射 HandlerMapping 解析请求对应的 Handler -> HandlerAdapter 会根据 Handler 来调用真正的处理器来处理请求,并处理相应的业务逻辑 -> 处理器返回一个模型视图 ModelAndView -> 视图解析器进行解析 -> 返回一个视图对象 -> 前端控制器 DispatcherServlet 渲染数据(Model)-> 将得到视图对象返回给用户。
流程

上图用于辅助理解,面试时可用下列 8 步描述 SpringMVC 运行流程:
1. 用户向服务器发送请求,请求被 Spring 前端控制Servelt DispatcherServlet 捕获;
2. DispatcherServlet 对请求 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 对象的形式返回;
3. DispatcherServlet 根据获得的 Handler,选择一个合适的HandlerAdapter;(附注:如果成功获得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(…)方法)
4. 提取 Request 中的模型数据,填充 Handler 入参,开始执行Handler(Controller)。在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:
(1)HttpMessageConveter:将请求消息(如:Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息;
(2)数据转换:对请求消息进行数据转换。如:String 转换成 Integer、Double 等;
(3)数据格式化:对请求消息进行数据格式化。如:将字符串转换成格式化数字或格式化日期等;
(4)数据验证:验证数据的有效性(长度、格式等),验证结果存储到 BindingResult 或 Error 中;
5. Handler 执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象;
6. 根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的 ViewResolver)返回给DispatcherServlet;
7. ViewResolver 结合 Model 和 View,来渲染视图;
8. 将渲染结果返回给客户端。

3、SpringMVC 的核心组件有哪些?

  • 1. 前端控制器 DispatcherServlet

作用:Spring MVC 的入口函数。接收请求,响应结果,相当于转发器,中央处理器。有了 DispatcherServlet 减少了其它组件之间的耦合度。用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。

  • 2. 处理器映射器 HandlerMapping

作用:根据请求的 url 查找 Handler。HandlerMapping 负责根据用户请求找到 Handler 即处理器(Controller),SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

  • 3. 处理器适配器 HandlerAdapter

作用:按照特定规则(HandlerAdapter 要求的规则)去执行 Handler。通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

  • 4. 处理器 Handler

注意:编写 Handler 时按照 HandlerAdapter 的要求去做,这样适配器才可以去正确执行 Handler。Handler 是继 DispatcherServlet 前端控制器的后端控制器,在 DispatcherServlet 的控制下 Handler 对具体的用户请求进行处理。由于 Handler 涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发 Handler。

  • 5. 视图解析器 View resolver

作用:进行视图解析,根据逻辑视图名解析成真正的视图(View )。View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。SpringMVC 框架提供了很多的 View 视图类型,包括:jstlView、freemarkerView、pdfView 等。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。

  • 6. 视图 View

View 是一个接口,实现类支持不同的 View 类型(jsp、freemarker…)。
注意:处理器 Handler(也就是我们平常说的 Controller 控制器)以及视图层 View 都是需要我们自己手动开发的。其他的一些组件比如:前端控制器 DispatcherServlet、处理器映射器 HandlerMapping、处理器适配器 HandlerAdapter 等等都是框架提供给我们的,不需要自己手动开发。

4、SpringMVC 常用的注解有哪些?

  1. @RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径;
    2. @RequestBody:注解实现接收 HTTP 请求的 json 数据,将 json 转换为 Java 对象;
    3. @ResponseBody:注解实现将 Controller 方法返回对象转化为 json 对象响应给客户。

    5、@RequestMapping 的作用是什么?

    RequestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。RequestMapping 注解有六个属性,下面我们把它分成三类进行说明。
  • value、method:
  1. value:指定请求的实际地址,指定的地址可以是 URI Template 模式;
    2. method:指定请求的method类型, GET、POST、PUT、DELETE 等;
  • consumes、produces:
  1. consumes:指定处理请求的提交内容类型(Content-Type),例如 application/json、text/html;
    2. produces:指定返回的内容类型,仅当 request 请求头中的(Accept)类型中包含该指定类型才返回;
  • params、header:
  1. params:指定 request 中必须包含某些参数值是,才让该方法处理。
    2. headers:指定 request 中必须包含某些指定的 header 值,才能让该方法处理请求。

    6、如何解决 POST 请求中文乱码问题,GET 的又如何处理呢?

    1.解决 POST 请求乱码问题:在 web.xml 中配置一个 CharacterEncodingFilter 过滤器,设置成 utf-8;
    2. GET 请求中文参数出现乱码解决方法有两个:
    (1)修改 tomcat 配置文件添加编码与工程编码一致,如下:
    1. <ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
    (2)对参数进行重新编码:
    1. String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

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

    是单例模式,所以在多线程访问的时候有线程安全问题。但是不要使用同步,会影响性能,解决方案是在控制器里面不能写字段。

    8、SpringMVC 怎么样设定重定向和转发的?

  2. 转发:在返回值前面加 “forward:”,譬如:
    1. "forward:user.do?name=method2"
  3. 重定向:在返回值前面加 “redirect:”,譬如:
    1. "redirect:http://www.zju.com"

    9、SpringMVC 里面拦截器是怎么写的?

    方法一:实现 HandlerInterceptor 接口;
    方法二:继承适配器类,接着在接口方法当中,实现处理逻辑,然后在 SpringMVC 的配置文件中配置拦截器即可。

    10、SpringMVC 和 Struts2 的区别有哪些?

  4. SpringMVC 的入口是一个 Servlet 即前端控制器(DispatchServlet),而 Struts2 入口是一个 filter 过虑器(StrutsPrepareAndExecuteFilter);
    2. SpringMVC 是基于方法开发(一个 url 对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),Struts2 是基于类开发,传递参数是通过类的属性,只能设计为多例;
    3. Struts2 采用值栈存储请求和响应的数据,通过 OGNL 存取数据;SpringMVC 通过参数解析器是将 request 请求内容解析,并给方法形参赋值,将数据和视图封装成 ModelAndView 对象,最后又将 ModelAndView 中的模型数据通过 request 域传输到页面。jsp 视图解析器默认使用 jstl。


    11、什么是 Spring MVC?

    SpringMvc 是 spring 的一个模块,基于 MVC 的一个框架,无需中间整合层来整合。

    12、Spring MVC 的优点:

    1)它是基于组件技术的.全部的应用对象,无论控制器和视图,还是业务对象之类的都是 java
    组件.并且和 Spring 提供的其他基础结构紧密集成.
    2)不依赖于 Servlet API(目标虽是如此,但是在实现的时候确实是依赖于 Servlet 的)
    3)可以任意使用各种视图技术,而不仅仅局限于 JSP
    4)支持各种请求资源的映射策略
    5)它应是易于扩展的

MyBatis

1、谈谈你对 MyBatis 的理解?

  1. Mybatis是一个半ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建 Statement 等繁杂的过程。程序员直接编写原生态 SQL,可以严格控制 SQL 执行性能,灵活度高。
    2. MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
    3. 通过 XML 文件或注解的方式将要执行的各种 Statement 配置起来,并通过 Java 对象和 Statement 中 SQL 的动态参数进行映射生成最终执行的 SQL 语句,最后由 MyBatis 框架执行 SQL并将结果映射为 Java 对象并返回。(从执行 SQL到返回 Result 的过程)。

    2、MyBaits 的优缺点有哪些?

  • 优点:
  1. 基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL 写在 XML 里,解除 SQL 与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态 SQL 语句,并可重用;
    2. 与 JDBC 相比,减少了代码量,消除了 JDBC 大量冗余的代码,不需要手动开关连接;
    3. 很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数据库 MyBatis 都支持);
    4. 提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射标签,支持对象关系组件维护。
  • 缺点:
  1. SQL 语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写 SQL 语句的功底有一定要求;
    2. SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

    3、MyBatis 与 Hibernate 有哪些不同?

  2. MyBatis 和 Hibernate不同,它不完全是一个 ORM 框架,因为 MyBatis 需要程序员自己编写 SQL 语句;Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用 Hibernate 开发可以节省很多代码,提高效率;
    2. MyBatis 直接编写原生态 SQL,可以严格控制 SQL 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是 MyBatis 无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套 SQL 映射文件,工作量大。

    4、MyBatis 中 #{} 和 ${}的区别是什么?

  • #{} 是预编译处理,${} 是字符串替换
  1. Mybatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ? 号,调用 PreparedStatement 的 set 方法来赋值;使用 #{} 可以有效的防止 SQL 注入,提高系统安全性;
    2. MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。

    5、MyBatis 是如何进行分页的?分页插件的原理是什么?

    MyBatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非物理分页。可以在 SQL 内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
    分页插件的基本原理是使用 MyBatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 SQL,然后重写 SQL,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。

    6、MyBatis 有几种分页方式?

  2. 数组分页
    2. SQL 分页
    3. 拦截器分页
    4. RowBounds 分页

    7、MyBatis 逻辑分页和物理分页的区别是什么?

  3. 物理分页速度上并不一定快于逻辑分页,逻辑分页速度上也并不一定快于物理分页。
    2. 物理分页总是优于逻辑分页:没有必要将属于数据库端的压力加到应用端来,就算速度上存在优势,然而其它性能上的优点足以弥补这个缺点。

    8、MyBatis 是否支持延迟加载?如果支持,它的实现原理是什么?

    Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在MyBatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
    它的原理是,使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName(),拦截器 invoke() 方法发现 a.getB() 是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 SQL,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName() 方法的调用。这就是延迟加载的基本原理。

    9、说一下 MyBatis 的一级缓存和二级缓存?

    一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存;
    二级缓存:与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态),可在它的映射文件中配置
    对于缓存数据更新机制,当某一个作用域(一级缓存 Session / 二级缓存 Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。

    10、Mybatis 有哪些执行器(Executor)?

    Mybatis 有 3 种基本的执行器(Executor):
    1. SimpleExecutor:每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象;
    2. ReuseExecutor:执行 update 或 select,以 SQL 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map 内,供下一次使用。简言之,就是重复使用 Statement 对象;
    3. BatchExecutor:执行 update(没有 select,JDBC 批处理不支持select),将所有 SQL 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement对 象都是 addBatch() 完毕后,等待逐一执行 executeBatch() 批处理。与 JDBC 批处理相同。

    11、MyBatis 动态 SQL 是做什么的?都有哪些动态 SQL?能简述一下动态 SQL的执行原理不?

  4. MyBatis 动态 SQL 可以让我们在 XML 映射文件内,以标签的形式编写动态 SQL,完成逻辑判断和动态拼接 SQL 的功能;
    2. MyBatis 提供了 9 种动态 SQL 标签:trim、where、set、foreach、if、choose、when、otherwise、bind;
    3. 执行原理:使用 OGNL 从 SQL 参数对象中计算表达式的值,根据表达式的值动态拼接 SQL,以此来完成动态 SQL 的功能。