Spring 面试题

Spring面试题


1 IoC 属于哪种设计模式?

工厂模式


2 (2)谈谈你对 Spring IoC 和 DI 的理解,它们有什么区别?

IoC Inverse of Control 反转控制的概念,就是将原本在程序中手动创建 UserService 对象的控制权,交由 Spring 框架管理,简单说就是创建 UserService 对象控制权被反转到了 Spring 框架。

DI:Dependency Injection 依赖注入,在 Spring 框架负责创建 Bean 对象时,动态的将依赖对象注入到 Bean 组件。


(3)简单谈谈 IoC 容器的原理。

IoC 容器在加载时对 XML 配置文件进行解析,获取所有的 bean 配置,结合 bean 中的信息(实体类,属性),通过反射机制来创建实例化对象并完成成员变量的赋值操作,最后以键值对的形式将创建好的实例化对象存入容器。


(4)bean 的 scope 有几种类型?请详细列举。

共有 4 种。

singleton:单例,表示通过 Spring 容器获取的该对象是唯一的。
prototype:原型,表示通过 Spring 容器获取的对象都是不同的。
reqeust:请求,表示在一次 HTTP 请求内有效。
session:会话,表示在一个用户会话内有效。


(5)说说 IoC 中的继承和 Java 继承的区别。

IoC 中继承是对象层面的,指继承对象可以获取被继承对象的所有成员变量值,并赋给其对应的成员变量。Java 中的继承是类层面的,指子类可以获取父类的非私有成员变量和方法,不需要再次定义。


(6)IoC 中 car 对象的配置如下,现在要添加 user 对象,并且将 car 注入到 user 中
<bean id="user" class="com.southwind.entity.User"><property name="car" ref="car"></property>

  </bean>
<bean id="user" class="com.southwind.entity.User" p:car-ref="car"></bean>
(7) 请分别写出 IoC 静态工厂方法和实例工厂方法的配置。
<!-- 配置静态工厂创建 car 对象 -->
<bean id="car1" class="com.southwind.entity.StaticCarFactory" factory-method="getCar">
<constructor-arg value="1"></constructor-arg>
</bean>

<!-- 配置实例工厂对象 -->
<bean id="carFactory" class="com.southwind.entity.InstanceCarFactory"></bean>

<!-- 通过实例工厂对象创建 car 对象 -->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="2"></constructor-arg>
</bean> 

(8)IoC 自动装载有几种方式?

有两种。

byName:通过属性名自动装载。
byType:通过属性对应的数据类型自动装载。


(9)介绍一下 Spring 框架中 bean 的生命周期。

1)bean 定义:在配置文件里面用 来进行定义。

2)bean初始化,有两种方式初始化:

在配置文件中通过指定 init-method 属性来完成;
实现 org.springframwork.beans.factory.InitializingBean 接口。
3)bean 调用。

4)bean 销毁,销毁有两种方式:

使用配置文件指定的 destroy-method 属性
实现 org.springframwork.bean.factory.DisposeableBean 接口


(10)IoC 容器自动完成装载,默认是 什么的方式?

byType


(11)Spring AOP 的原理是什么?都有哪些具体的应用场景?

  • AOP:Aspect Oriented Programming 面向切面编程,用来封装横切关注点,具体可以在下面的场景中使用:Authentication 权限、Caching 缓存、Context passing 内容传递、Error handling 错误处理 Lazy loading 懒加载、Debugging 调试、logging、tracing、profiling and monitoring 记录跟踪优化校准、Performance optimization 性能优化、Persistence 持久化、Resource pooling 资源池、Synchronization 同步、Transactions 事务。
  • 原理:AOP 是面向切面编程,是通过动态代理的方式为程序添加统一功能,集中解决一些公共问题。
    优点:
  • 1)各个步骤之间的良好隔离性使得耦合性大大降低;
  • 2)源代码无关性,扩展功能的同时不对源码进行修改操作。

12.@Value 注解的作用是什么?

基于 @Value 的注解可以读取 properties 配置文件,使用如下:

13.Spring 通知类型有哪些?

Spring 通知类型总共有 5 种:前置通知、环绕通知、后置通知、异常通知、最终通知。

  • 前置通知(Before advice):在目标方法执行之前执行的通知。在某连接点( join point )之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
  • 环绕通知(Around Advice):在目标方法执行之前和之后都可以执行额外代码的通知,也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
  • 后置通知(After (finally) advice):目标方法执行之后(某连接点退出的时候)执行的通知(不论是正常返回还是异常退出)。
  • 异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
  • 最终通知(After returning advice):在某连接点(join point)正常完成后执行的通知,例如,一个方法没有抛出任何异常,正常返回。

14.怎么理解 Spring 中的 IOC 容器?

Spring IOC 就是把创建对象的权利交给框架去控制,而不需要人为的去创建,这样就实现了可插拔式的接口编程,有效地降低代码的耦合度,降低了扩展和维护的成本。

15 怎么理解 Spring 中的依赖注入?

依赖注入是指组件之间的依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

16.IoC 和 DI 有什么关系?

IoC 是 Spring 中一个极为重要的概念,提供了对象管理的功能,从而省去了人为创建麻烦,而 DI 正是实现 IoC 的方法和手段。

17.@Component 和 @Bean 有什么区别?

它们的作用对象不同:@Component 作用于类,而 @Bean 注解作用于方法。

@Component 通常是通过类路径扫描来自动侦测和装配对象到 Spring 容器中,比如 @ComponentScan 注解就是定义扫描路径中的类装配到 Spring 的 Bean 容器中;@Bean 注解是告诉 Spring 这是某个类的实例,当我需要用它的时把它给我,@Bean 注解比 @Component 注解自定义性更强,很多地方我们只能通过 @Bean 注解来注册 Bean,比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean 来实现,比如以下示例,只能通过 @Bean 注解来实现:

public class Config{
    @Bean
    public Test test() {
        return new Test();
    }
}

18.Spring 中 bean 的作用域有几种类型?

Spring 中 bean 的作用域有四种类型,如下列表:

  • 单例(Singleton):整个应用程序,只创建 bean 的一个实例;
  • 原型(Prototype):每次注入都会创建一个新的 bean 实例;
  • 会话(Session):每个会话创建一个 bean 实例,只在 Web 系统中有效;
  • 请求(Request):每个请求创建一个 bean 实例,只在 Web 系统中有效。

Spring 默认的是单例模式。

19.什么是 Spring 的内部 bean?

当一个 bean 仅被用作另一个 bean 的属性时,它能被声明为一个内部 bean,为了定义 inner Bean,在 Spring 的基于 XML 的配置元数据中,可以在 或 元素内使用 元素,内部 bean 通常是匿名的,它们的 Scope 一般是 prototype。

20.Spring 注入方式有哪些?

Spring 的注入方式包含以下五种:

  • setter 注入
  • 构造方法注入
  • 注解注入
  • 静态工厂注入
  • 实例工厂注入

其中最常用的是前三种,官方推荐使用的是注解注入,相对使用更简单,维护成本更低,更直观。

21.在 Spring 中如何操作数据库?

在 Spring 中操作数据库,可以使用 Spring 提供的 JdbcTemplate 对象,JdbcTemplate 类提供了很多便利的方法,比如把数据库数据转变成基本数据类型或对象,执行自定义的 SQL 语句,提供了自定义的数据错误处理等,JdbcTemplate 使用示例如下:

@Autowired
private JdbcTemplate jdbcTemplate;

22.Spring 的 JdbcTemplate 对象和 JDBC 有什么区别?

Spring 的 JdbcTemplate 是对 JDBC API 的封装,提供更多的功能和更便利的操作,比如 JdbcTemplate 拥有:

  • JdbcTemplate 是线程安全的;
  • 实例化操作比较简单,仅需要传递 DataSource;
  • 自动完成资源的创建和释放工作;
  • 创建一次 JdbcTemplate,到处可用,避免重复开发。

23.Spring 有几种实现事务的方式?

Spring 实现事务有两种方式:编程式事务和声明式事务。
编程式事务,使用 TransactionTemplate 或 PlatformTransactionManager 实现,示例代码如下:

private final TransactionTemplate transactionTemplate;
public void add(User user) throws Exception{
    // Spring编码式事务,回调机制
    transactionTemplate.execute(new TransactionCallback<Object>() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
            try {
                userMapper.insertSelective(user);
            } catch (Exception e) {
                // 异常,设置为回滚
                status.setRollbackOnly();
                throw e;
            }
            return null;
        }
    });
}

如果有异常,调用 status.setRollbackOnly() 回滚事务,否则正常执行 doInTransaction() 方法,正常提交事务。
如果事务控制的方法不需要返回值,就可以使用 TransactionCallbackWithoutResult(TransactionCallback 接口的抽象实现类)示例代码如下:

public void add(User user) throws Exception {
    // Spring编码式事务,回调机制
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            try {
                userMapper.insertSelective(user);
            } catch (Exception e) {
                // 异常,设置为回滚
                status.setRollbackOnly();
                throw e;
            }
        }
    });
}

声明式事务,底层是建立在 Spring AOP 的基础上,在方式执行前后进行拦截,并在目标方法开始执行前创建新事务或加入一个已存在事务,最后在目标方法执行完后根据情况提交或者回滚事务。
声明式事务的优点:不需要编程,减少了代码的耦合,在配置文件中配置并在目标方法上添加 @Transactional 注解来实现,示例代码如下:

@Transactional
public void save() {
    User user = new User("laowang");
    userMapper.insertSelective(user);
    if (true) {
        throw new RuntimeException("异常");
    }
}

抛出异常,事务会自动回滚,如果方法正常执行,则会自动提交事务。

24.Spring 事务隔离级别有哪些?

Spring 的注入方式包含以下五种:

  • ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
  • ISOLATIONREADUNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
  • ISOLATIONREADCOMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
  • ISOLATIONREPEATABLEREAD:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
  • ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
  • 默认值为 ISOLATION_DEFAULT 遵循数据库的事务隔离级别设置。

25.Spring 声明式事务无效可能的原因有哪些?

可能的原因如下:

  • MySQL 使用的是 MyISAM 引擎,而 MyISAM 是不支持事务的;
  • @Transactional 使用在非 public 方法上,@Transactional 注解只能支持 public 级别,其他类型声明的事务不会生效;
  • @Transactional 在同一个类中无事务方法 A() 内部调用有事务方法 B(),那么此时 B() 事物不会生效。

26 Spring 中的 AOP 的底层实现原理是什么?

Spring AOP 的底层实现原理就是动态代理。Spring AOP 的动态代理有两种实现方式,对于接口使用的是 JDK 自带的动态代理来实现的,而对比非接口使用的是 CGLib 来实现的,关于动态代理的详细内容,可参考前面【反射和动态代理】的那篇文章。

27.Spring 中的 Bean 是线程安全的吗?

Spring 中的 Bean 默认是单例模式,Spring 框架并没有对单例 Bean 进行多线程的封装处理,因此默认的情况 Bean 并非是安全的,最简单保证 Bean 安全的举措就是设置 Bean 的作用域为 Prototype(原型)模式,这样每次请求都会新建一个 Bean。

28.说一下 Spring 中 Bean 的生命周期?

Spring 中 Bean 的生命周期如下:

  • ① 实例化 Bean:对于 BeanFactory 容器,当客户向容器请求一个尚未初始化的 Bean 时,或初始化 Bean 的时候需要注入另一个尚未初始化的依赖时,容器就会调用 createBean 进行实例化。对于 ApplicationContext 容器,当容器启动结束后,通过获取 BeanDefinition 对象中的信息,实例化所有的 Bean;

  • ② 设置对象属性(依赖注入):实例化后的对象被封装在 BeanWrapper 对象中,紧接着 Spring 根据 BeanDefinition 中的信息以及通过 BeanWrapper 提供的设置属性的接口完成依赖注入;

  • ③ 处理 Aware 接口:Spring 会检测该对象是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给 Bean:
    如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String BeanId) 方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值;
    如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory() 方法,传递的是 Spring 工厂自身;
    如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用 setApplicationContext(ApplicationContext) 方法,传入 Spring 上下文;

  • ④ BeanPostProcessor:如果想对 Bean 进行一些自定义的处理,那么可以让 Bean 实现了 BeanPostProcessor 接口,那将会调用 postProcessBeforeInitialization(Object obj, String s) 方法;

  • ⑤ InitializingBean 与 init-method:如果 Bean 在 Spring 配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法;

  • ⑥ 如果这个 Bean 实现了 BeanPostProcessor 接口,将会调用 postProcessAfterInitialization(Object obj, String s) 方法;由于这个方法是在 Bean 初始化结束时调用的,因而可以被应用于内存或缓存技术;
    以上几个步骤完成后,Bean 就已经被正确创建了,之后就可以使用这个 Bean 了。

  • ⑦ DisposableBean:当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy() 方法;

  • ⑧ destroy-method:最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。

29.Spring 有哪些优点?

Spring 优点如下:

  • 开源免费的热门框架,稳定性高、解决问题成本低;
  • 方便集成各种优秀的框架;
  • 降低了代码耦合性,通过 Spring 提供的 IoC 容器,我们可以将对象之间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合;
  • 方便程序测试,在 Spring 里,测试变得非常简单,例如:Spring 对 Junit 的支持,可以通过注解方便的测试 Spring 程序;
  • 降低 Java EE API 的使用难度,Spring 对很多难用的 Java EE API(如 JDBC、JavaMail、远程调用等)提供了一层封装,通过 Spring 的简易封装,让这些 Java EE API 的使用难度大为降低。

30.Spring 和 Struts 的区别?

Spring 和 Struts 区别如下:
Spring 特性如下:

  • 具备 IOC/DI、AOP 等通用能力,提高研发效率
  • 除了支持 Web 层建设以外,还提供了 J2EE 整体服务
  • 方便与其他不同技术结合使用,如 Hibernate、MyBatis 等
  • Spring 拦截机制是方法级别

Struts 特性如下:

  • 是一个基于 MVC 模式的一个 Web 层的处理
  • Struts 拦截机制是类级别

31.Spring、SpringBoot、SpringCloud 的区别是什么?

它们的区别如下:

  • Spring Framework 简称 Spring,是整个 Spring 生态的基础。
  • Spring Boot 是一个快速开发框架,让开发者可以迅速搭建一套基于 Spring 的应用程序,并且将常用的 Spring 模块以及第三方模块,如 MyBatis、Hibernate 等都做了很好的集成,只需要简单的配置即可使用,不需要任何的 XML 配置文件,真正做到了开箱即用,同时默认支持 JSON 格式的数据,使用 Spring Boot 进行前后端分离开发也非常便捷。
  • Spring Cloud 是一套整合了分布式应用常用模块的框架,使得开发者可以快速实现微服务应用。作为目前非常热门的技术,有关微服务的话题总是在各种场景下被大家讨论,企业的招聘信息中也越来越多地出现对于微服务架构能力的要求。

32.Spring 中都是用了哪些设计模式?

Spring 中使用的设计模式如下:

  • 工厂模式:通过 BeanFactory、ApplicationContext 来创建 bean 都是属于工厂模式;
    单例、原型模式:创建 bean 对象设置作用域时,就可以声明 Singleton(单例模式)、Prototype(原型模式);
  • 察者模式:Spring 可以定义一下监听,如 ApplicationListener 当某个动作触发时就会发出通知;
  • 责任链模式:AOP 拦截器的执行;
  • 策略模式:在创建代理类时,如果代理的是接口使用的是 JDK 自身的动态代理,如果不是接口使用的是 CGLIB 实现动态代理。

Sprint MVC 专题」面试题


(1)谈谈你对 MVC 的理解。

MVC 设计模式是一种常用的软件架构方式:以 Controller(控制层)、Model(模型层)、View(视图层)三个模块分离的形式来组织代码。
MVC 工作流程:控制层接受到客户端请求,调用模型层生成业务数据,传递给视图层,将最终的业务数据和视图响应给客户端做展示。


(2)什么是 Spring MVC ?简单介绍下你对 Spring MVC 的理解?

MVC 是一种流行的架构方式,通过将 Model、View、Controller 进行分离,把较为复杂的 Web 应用分成逻辑清晰的模块,简化开发、提高效率,方便组内开发人员之间的配合,Spring MVC 就是一个实现 MVC 设计模式的企业级框架,它是 Spring 的一个子模块,可以非常方便地进行整合。


(3)Spring MVC 有哪些优点?

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

(4)Spring MVC 的核心组件有哪些?

  • DispatcherServlet:前端控制器,是整个流程控制的核心,控制其他组件的执行,统一调度,降低组件之间的耦合性,相当于总指挥。
  • Handler:处理器,完成具体业务逻辑,相当于 Servlet 或 Action。
  • HandlerMapping:DispatcherServlet 接收到请求之后,通过 HandlerMapping 将不同的请求分发到不同的 Handler。
  • HandlerInterceptor:处理器拦截器,是一个接口,如果我们需要做一些拦截处理,可以来实现这个接口。
  • HandlerExecutionChain:处理器执行链,包括两部分内容:Handler 和 HandlerInterceptor(系统会有一个默认的 HandlerInterceptor,如果需要额外拦截处理,可以添加拦截器设置)。
  • HandlerAdapter:处理器适配器,Handler 执行业务方法之前,需要进行一系列的操作包括表单数据的验证,数据类型的转换,将表单数据封装到 POJO 等,这一系列的操作,都是由 HandlerAdapter 来完成,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。
  • ModelAndView:装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
  • ViewResolver:视图解析器,DispatcherServlet 通过它将逻辑视图解析成物理视图,最终将渲染结果响应给客户端。

(5)Spring MVC 的实现流程是什么?

  • 客户端请求被 DispatcherServlet(前端控制器)接收。
  • 根据 HandlerMapping 映射到 Handler。
  • 生成 Handler 和 HandlerInterceptor(如果有则生成)。
  • Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式一并返回给 DispatcherServlet。
  • DispatcherServlet 通过 HandlerAdapter 调用 Handler 的方法做业务逻辑处理。
  • 返回一个 ModelAndView 对象给 DispatcherServlet。
  • DispatcherServlet 将获取的 ModelAndView 对象传给 ViewResolver 视图解析器,将逻辑视图解析成物理视图 View。
  • ViewResolver 返回一个 View 给 DispatcherServlet。
  • DispatcherServlet 根据 View 进行视图渲染(将模型数据填充到视图中)。
  • DispatcherServlet 将渲染后的视图响应给客户端。

(6)Spring MVC 怎样设定重定向和转发?

在返回值前面加 “forward:” 就可以让结果转发,譬如 “forward:user.do?name=zhangsan”。
在返回值前面加 “redirect:” 就可以让返回值重定向,譬如 “redirect:index.jsp”。

(7)如何解决 POST 请求和 GET 请求的中文乱码问题?

1)解决 POST 请求乱码问题。

在 web.xml 中加入:

  <filter>
  <filter-name>CharacterEncodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
  <param-name>encoding</param-name>
  <param-value>utf-8</param-value>
  </init-param>
  </filter>

  <filter-mapping>
  <filter-name>CharacterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
  </filter-mapping>

2)GET 请求中文参数出现乱码解决方法有两个。

修改 Tomcat 配置文件添加编码与工程编码一致,如下:
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

3)另外一种方法对参数进行重新编码:

String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8");


(8)@ModelAttribute 注解应该如何使用?
  • 定义一个方法,该方法用来返回要填充到模型数据中的对象。
  • 给该方法添加 @ModelAttribute 注解。
  • 添加 @ModelAttribute 注解的方法,会在 Spring MVC 在调用任何一个业务方法之前被自动调用。

(9)说说你对自定义数据类型转换器的理解。

  • 通过自定义数据类型转换器可以根据需求对 HTTP 请求中的参数进行解析,转换成需要的数据类型。具体操作是创建一个 Java 类,实现 org.springframework.core.convert.converter.Converter 接口,这样自定义的 Java 类就具备了转换数据的功能,然后在 convert 方法中完成转换的具体业务流程。

  • 当服务器接收到一个请求之后,Spring MVC 首先将请求分发到数据类型转换器进行格式转换,然后再进入相应的业务方法。


(10)使用 Hibernate Validator 注解方式校验 Email 数据格式应该怎么写?
@Email(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$", message = "请输入正确的邮箱格式")
private String email;
11. 简述一下 Spring MVC 的执行流程?

前端控制器(DispatcherServlet) 接收请求,通过映射从 IoC 容器中获取对应的 Controller 对象和 Method 方法,在方法中进行业务逻辑处理组装数据,组装完数据把数据发给视图解析器,视图解析器根据数据和页面信息生成最终的页面,然后再返回给客户端。

12. POJO 和 JavaBean 有什么区别?

POJO 和 JavaBean 的区别如下:

  • POJO(Plain Ordinary Java Object)普通 Java 类,具有 getter/setter 方法的普通类都就可以称作 POJO,它是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。

  • JavaBean 是 Java 语言中的一种可重用组件,JavaBean 的构造函数和行为必须符合特定的约定:这个类必须有一个公共的缺省构造函数;这个类的属性使用 getter/setter 来访问,其他方法遵从标准命名规范;这个类应是可序列化的。
    简而言之,当一个 POJO 可序列化,有一个无参的构造函数,它就是一个 JavaBean。

13. 如何实现跨域访问?

常见的跨域的实现方式有两种:使用 JSONP 或者在服务器端设置运行跨域。服务器运行跨域的代码如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyConfiguration {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                // 设置允许跨域的请求规则
                registry.addMapping("/api/**");
            }
        };
    }
}
14. 以下代码描述正确的是?
@RequestMapping(value="/list",params={"age=10"}
public String list(){
   // do something
}
A:age 参数不传递的时候,默认值是 10
B:age 参数可以为空
C:age 参数不能为空
D:以上都不对

答:C
params={“age=10”} 表示必须包含 age 参数,且值必须等于 10。

15. @RequestMapping 注解的常用属性有哪些?

@RequestMapping 常用属性如下:

  • value:指定 URL 请求的实际地址,用法:@RequestMapping(value="/index");
  • method:指定请求的 method 类型,如 GET/POST/PUT/DELETE 等,用法:@RequestMapping(value="/list",method=RequestMethod.POST);
  • params:指定请求参数中必须包含的参数名称,如果不存在该名称,则无法调用此方法,用法:@RequestMapping(value="/list",params={“name”,“age”})。
16. 访问以下接口不传递任何参数的情况下,执行的结果是?
@RequestMapping(value="/list")
@ResponseBody
public String list(int id){
    return "id="+id;
}
A:id=0
B:id=
C:页面报错 500
D:id=null

答:C
页面报错会提示:可选的参数“id”不能转为 null,因为基本类型不能赋值 null,所以会报错。

17.访问页面时显示 403 代表的含义是?

常用 HTTP 状态码及对应的含义:

  • 400:错误请求,服务器不理解请求的语法
  • 401:未授权,请求要求身份验证
  • 403:禁止访问,服务器拒绝请求
  • 500:服务器内部错误,服务器遇到错误,无法完成请求
  • 502:错误网关,服务器作为网关或代理,从上游服务器收到无效响应
  • 504:网关超时,服务器作为网关或代理,但是没有及时从上游服务器收到请求
18.forward 和 redirect 有什么区别?

forward 和 redirect 区别如下:

  • forward 表示请求转发,请求转发是服务器的行为;redirect 表示重定向,重定向是客户端行为;
  • forward 是服务器请求资源,服务器直接访问把请求的资源转发给浏览器,浏览器根本不知道服务器的内容是从哪来的,因此它的地址栏还是原来的地址;redirect 是服务端发送一个状态码告诉浏览器重新请求新的地址,因此地址栏显示的是新的 URL;
  • forward 转发页面和转发到的页面可以共享 request 里面的数据;redirect 不能共享数据;
    从效率来说,forward 比 redirect 效率更高。
19. 访问以下接口不传递任何参数的情况下,执行的结果是?
@RequestMapping(value="/list")
@ResponseBody
public String list(Integer id){
    return "id="+id;
}
A:id=0
B:id=
C:页面报错 500
D:id=null

答:D

包装类可以赋值 null,不会报错。

20. Spring MVC 中如何在后端代码中实现页面跳转?

在后端代码中可以使用 forward:/index.jsp 或 redirect:/index.jsp 完成页面跳转,前者 URL 地址不会发生改变,或者 URL 地址会发生改变,完整跳转代码如下:

@RequestMapping("/redirect")
public String redirectTest(){
    return "redirect:/index.jsp";
}
21. Spring MVC 的常用注解有哪些?

Spring MVC 的常用注解如下:

  • @Controller:用于标记某个类为控制器;
  • @ResponseBody :标识返回的数据不是 html 标签的页面,而是某种格式的数据,如 JSON、XML 等;
  • @RestController:相当于 @Controller 加 @ResponseBody 的组合效果;
  • @Component:标识为 Spring 的组件;
  • @Configuration:用于定义配置类;
  • @RequestMapping:用于映射请求地址的注解;
  • @Autowired:自动装配对象;
  • @RequestHeader:可以把 Request 请求的 header 值绑定到方法的参数上。
22. 拦截器的使用场景有哪些?

拦截器的典型使用场景如下:

  • 日志记录:可用于记录请求日志,便于信息监控和信息统计;
  • 权限检查:可用于用户登录状态的检查;
  • 统一安全处理:可用于统一的安全效验或参数的加密 / 解密等。
23. Spring MVC 如何排除拦截目录?

在 Spring MVC 的配置文件中,添加 ,用于排除拦截目录,完整配置的示例代码如下:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
        <!-- 排除拦截地址 -->
        <mvc:exclude-mapping path="/api/**" />
        <bean class="com.learning.core.MyInteceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>
24.@Validated 和 @Valid 有什么区别 ?

@Validated 和 @Valid 都用于参数的效验,不同的是:

  • @Valid 是 Hibernate 提供的效验机制,Java 的 JSR 303 声明了 @Valid 这个类接口,而 Hibernate-validator 对其进行了实现;@Validated 是 Spring 提供的效验机制,@Validation 是对 @Valid 进行了二次封装,提供了分组功能,可以在参数验证时,根据不同的分组采用不同的验证机制;
  • @Valid 可用在成员对象的属性字段验证上,而 @Validated 不能用在成员对象的属性字段验证上,也就是说 - @Validated 无法提供嵌套验证。
25.Spring MVC 有几种获取 request 的方式?

Spring MVC 获取 request 有以下三种方式:

从请求参数中获取

@RequestMapping("/index")
@ResponseBody
public void index(HttpServletRequest request){
  // do something
}

该方法实现的原理是 Controller 开始处理请求时,Spring 会将 request 对象赋值到方法参数中。

通过 RequestContextHolder上下文获取 request 对象


@RequestMapping("/index")
@ResponseBody
public void index(){
    ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = servletRequestAttributes.getRequest();
    // do something
}
 通过自动注入的方式

@Controller
public class HomeController{
    @Autowired
    private HttpServletRequest request; // 自动注入 request 对象
    // do something
}

MyBatis 专题」面试题


(1)简单谈谈你对 MyBatis 的理解?
  • Mybatis 是一个半自动化的 ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建 Statement 等繁杂的过程。程序员直接编写原生态 SQL,可以严格控制 SQL 执行性能,灵活度高。

  • MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

  • 通过 XML 文件或注解的方式将要执行的各种 Statement 配置起来,并通过 POJO 和 Statement 中 SQL 的动态参数进行映射生成最终执行的 SQL 语句,最后由 MyBatis 框架执行 SQL 并将结果映射为 POJO 并返回。


(2)MyBatis 接口绑定的优点是什么?

接口映射就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑定,开发者直接调用接口方法就即可,这样比起原生 SqlSession 提供的方法,开发者有了更加灵活的选择和设置。


(3)实现 MyBatis 接口绑定分别有哪几种方式?

接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面添加 @Select、@Update 等注解里面包含 SQL 语句来绑定;另外一种是通过在 XML 文件中编写 SQL 语句来绑定,这种情况下要指定 XML 映射文件里的 namespace 必须为接口的全路径名。


(4)MyBatis 如何实现一对一关联关系?
  • 有联合查询和嵌套查询,联合查询是几个表进行关联查询,只查询一次,通过在 resultMap 中配置 association节点配置一对一的映射就可以完成。
  • 嵌套查询是先查一个表,根据该表查询结果的外键 id,去另外一个表里面查询数据,通过 association 配置进行关联,但另外一个表的查询需要通过 select 属性进行配置。

(5)MyBatis 如何实现一对多关联关系?
  • 有联合查询和嵌套查询,联合查询是几个表进行关联查询,只查询一次,通过在 resultMap 中配置 collection 节点配置一对多的就可以完成。
  • 嵌套查询是先查一个表,根据该表查询结果的外键 id,去另外一个表里面查询数据,通过配置 collection 进行关联,但另外一个表的查询需要通过 select 属性进行配置。

(6)说说 MyBatis 动态 SQL 的具体使用步骤?

MyBatis 的动态 SQL 一般是通过 if 节点来实现,通过 OGNL 语法来实现,但是如果要写完整,必须配合 where、trim 节点,where 节点用来判断是否包含其他子节点,有的话就插入 where,否则不插入,trim 节点是用来判断如果动态语句是以 and 或 or 开始,那么会自动把这个 and 或者 or 去掉。


(7)MyBatis 与 Hibernate 的区别是什么?
  • Mybatis 和 Hibernate 不同,它不完全是一个 ORM 框架,因为 MyBatis 需要程序员自己编写 SQL 语句。

  • MyBatis 直接编写原生 SQL,可以严格控制 SQL 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是 MyBatis 无法做到数据库无关性,如果需要实现支持多种数据库的应用,则需要自定义多套 SQL 映射文件,工作量大。

  • Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的应用,用 Hibernate 开发可以节省很多代码,提高效率。


(8)MyBatis 如何实现模糊查询?
<select id="findAllByKeyWord" parameterType="java.lang.String" resultType="com.southwind.entity.Product">
  select * from easybuy_product where name like "%"#{keyWord}"%"
</select>

(9)Nginx 反向代理实现高并发的具体步骤是什么?
#tomcat集群
upstream  myapp {   #tomcat集群名称 
    server    localhost:8080;   #tomcat1配置
    server    localhost:8181;   #tomcat2配置
}

server {
    listen       9090;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
        #root   html;
        #index  index.html index.htm;
        proxy_pass http://myapp;
        proxy_redirect default;
    }
 }

10 MyBatis 执行流程说明:

  • 首先加载 Mapper 配置的 SQL 映射文件,或者是注解的相关 SQL 内容。
  • 创建会话工厂,MyBatis 通过读取配置文件的信息来构造出会话工厂(SqlSessionFactory)。
  • 创建会话,根据会话工厂,MyBatis 就可以通过它来创建会话对象(SqlSession),会话对象是一个接口,该接口中包含了对数据库操作的增、删、改、查方法。
  • 创建执行器,因为会话对象本身不能直接操作数据库,所以它使用了一个叫做数据库执行器(Executor)的接口来帮它执行操作。
  • 封装 SQL 对象,在这一步,执行器将待处理的 SQL 信息封装到一个对象中(MappedStatement),该对象包括 SQL 语句、输入参数映射信息(Java 简单类型、HashMap 或 POJO)和输出结果映射信息(Java 简单类型、HashMap 或 POJO)。
  • 操作数据库,拥有了执行器和 SQL 信息封装对象就使用它们访问数据库了,最后再返回操作结果,结束流程。

11.MyBatis 有哪些优缺点?

优点:

  • 相比于 JDBC 需要编写的代码更少
  • 使用灵活,支持动态 SQL
  • 提供映射标签,支持对象与数据库的字段关系映射

缺点:

  • SQL 语句依赖于数据库,数据库移植性差
  • SQL 语句编写工作量大,尤其在表、字段比较多的情况下

12.MyBatis 和 Hibernate 有哪些不同?

MyBatis 和 Hibernate 都是非常优秀的 ORM 框架,它们的区别如下:

  • 灵活性:MyBatis 更加灵活,自己可以写 SQL 语句,使用起来比较方便;
  • 可移植性:MyBatis 有很多自己写的 SQL,因为每个数据库的 SQL 可以不相同,所以可移植性比较差;
  • 开发效率:Hibernate 对 SQL 语句做了封装,让开发者可以直接使用,因此开发效率更高;
  • 学习和使用门槛:MyBatis 入门比较简单,使用门槛也更低。

13.“#”和“$”有什么区别?

“#”是预编译处理,“$”是字符替换。

在使用“#”时,MyBatis 会将 SQL 中的参数替换成“?”,配合 PreparedStatement 的 set 方法赋值,这样可以有效的防止 SQL 注入,保证程序的运行安全。

14 MyBatis 中怎么解决实体类属性名和表字段名不一致的问题?

  • sql 中可以使用 as 别名 框架会自动映射到字段

  • 使用 <resultMap> 自定义映射

15.在 MyBatis 中如何实现 like 查询?

like #{name};

16.MyBatis 有几种分页方式?

  • 逻辑分页,使用 MyBatis 自带的 RowBounds 进行分页,它是一次性查询很多数据,然后在数据中再进行检索;

  • 物理分页,自己手写 SQL 分页或使用分页插件 PageHelper,去数据库查询指定条数的分页数据形式。

17.什么是动态 SQL?

动态 SQL 是指可以根据不同的参数信息来动态拼接的不确定的 SQL 叫做动态 SQL,MyBatis 动态 SQL 的主要元素有:if、choose/when/otherwise、trim、where、set、foreach 等。

18.如何开启 MyBatis 的延迟加载?

在 mybatis-config.xml 设置 即可打开延迟缓存功能

<configuration>
    <settings>
        <!-- 开启延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
</configuration>

19 什么是 MyBatis 的一级缓存和二级缓存?

MyBatis 缓存如下:

  • 一级缓存是 SqlSession 级别的,是 MyBatis 自带的缓存功能,并且无法关闭,默认开启,因此当有两个 SqlSession 访问相同的 SQL 时,一级缓存也不会生效,需要查询两次数据库;

  • 二级缓存是 Mapper 级别的,只要是同一个 Mapper,无论使用多少个 SqlSession 来操作,数据都是共享的,多个不同的 SqlSession 可以共用二级缓存,MyBatis 二级缓存默认是关闭的,需要使用时可手动开启,二级缓存也可以使用第三方的缓存,比如,使用 Ehcache 作为二级缓存。

手动开启二级缓存,配置如下:

<configuration>
    <settings>
        <!-- 开启二级缓存 -->
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

20.MyBatis 有哪些拦截器?如何实现拦截功能?

MyBatis 提供的连接器有以下 4 种。

  • Executor:拦截内部执行器,它负责调用 StatementHandler 操作数据库,并把结果集通过 ResultSetHandler 进行自动映射,另外它还处理了二级缓存的操作。
  • StatementHandler:拦截 SQL 语法构建的处理,它是 MyBatis 直接和数据库执行 SQL 脚本的对象,另外它也实现了 MyBatis 的一级缓存。
  • ParameterHandler:拦截参数的处理。
  • ResultSetHandler:拦截结果集的处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TizzyGoodhealth

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值