Spring全家桶面经
- ========================Spring======================
- 1. Spring的IOC和AOP怎么理解?
- 2. Spring AOP里面的几个名词的概念? Spring AOP和AspectJ AOP有什么区别?
- 3. JDK动态代理和CGLIB动态代理的区别?
- 4. Spring通知(Advice)有哪些类型?
- 5. Spring中bean的作用域有哪些,有什么区别?
- 6. Spring 中的单例 bean 的线程安全问题了解吗?
- 7. @Component 和 @Bean 的区别是什么?
- 8. Spring 中的 bean 生命周期?你能重载什么方法吗?
- 9. 将一个类声明为Spring的bean的注解有哪些?
- 10. Spring事务中的隔离级别有哪几种?
- 11. Spring bean是什么?
- 12. IOC容器中用什么数据结构保存加载的bean对象?
- 13. SpringIOC容器的启动流程?
- 14. 什么是 Spring 框架? 列举一些重要的Spring模块?
- 15. Spring 事务中哪几种事务传播行为?
- 16. Spring事务的实现方式和实现原理?你能重载什么方法吗?
- 17. @Transactional(rollbackFor = Exception.class)注解了解吗?
- 18. 解决Spring事务异常回滚,捕获异常不抛出就不会回滚 ?
- 19. Spring项目启动的时候会加载哪些资源,顺序是怎么样的?
- 20. Spring中BeanFactory、FactoryBean和ApplicationContext的区别?
- 21. Spring如何解决循环依赖问题的过程?(三级缓存)
- 22. Spring基于xml注入bean的几种方式?
- 23. Spring 框架中用到了哪些设计模式?
- 24. Spring的自动装配(基于xml配置/基于注解)?
- 25. 什么是Spring中的依赖注入?依赖注入的基本原则?
- 26. Spring aop,什么时候会失效?
- 27. Spring的优缺点是什么?
- 28. Spring框架中有哪些不同类型的事件?
- 29. 在 Spring中如何注入一个java集合?
- 30. @Component, @Controller, @Repository, @Service 有何区别?
- 31. @Autowired和@Resource之间的区别?
- 32. @Qualifier 注解有什么作用?
- ========================SpringMVC========================
- 33. 说一下 springmvc的执行流程 ?
- 34. 什么是Spring MVC?简单介绍下你对Spring MVC的理解?
- 35. @RequestMapping 的作用是什么?
- 36. spring mvc 有哪些组件?
- 37. SpringMVC 常用注解都有哪些?
- 40. Spring MVC的优点?
- 41. 什么是DispatcherServlet?
- 42. Spring MVC的控制器是不是单例模式,如果是,有什么问题,怎么解决?
- 43. MVC是什么?MVC设计模式的好处有哪些?
- 44. Spring MVC的异常处理?
- 45. Spring MVC里面拦截器是怎么写的?
- ==================SpringBoot==================
- 46. SpringBoot的事务实现原理?
- 47. Spring Boot、Spring MVC 和 Spring 有什么区别?
- 48. Spring Boot 自动配置原理是什么?
- 49. 你如何理解 Spring Boot 中的 Starters?
- 50. 什么是 Spring Boot?
- 51. 为什么要用 Spring Boot?
- 52. Spring Boot 的核心配置文件有哪几个?bootstrap.properties 和 application.properties 有何区别 ?
- 53. Spring Boot 的配置文件有哪几种格式?它们有什么区别?什么是 YAML?
- 54. Spring Boot 有哪几种读取配置的方式?
- 55. Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
- 61. Spring Boot 有哪些优点?
- 62. Spring Boot 中如何解决跨域问题 ?
- 63. spring-boot-starter-parent 有什么用 ?
- 64. 运行 Spring Boot 有哪几种方式?
- 65. 如何使用 Spring Boot 实现异常处理?
- ======================MyBatis======================
- 66. MyBatis是什么?
- 67. ORM是什么?
- 68. 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
- 69. 传统JDBC开发存在的问题?JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?
- 70. Mybatis优缺点?
- 71. MyBatis编程步骤是什么样的?
- 72. 请说说MyBatis的工作原理?
- 73. Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
- 74. #{}和${}的区别?
- 75. 什么是MyBatis的接口绑定?有哪些实现方式?
- 76. 使用MyBatis的mapper接口调用时有哪些要求?
- 77. Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?
- 78. Mybatis是如何进行分页的?分页插件的原理是什么?
- 79. 缓存Mybatis的一级、二级缓存?
- 80. Hibernate 和 MyBatis 的区别?
- 81. MyBatis框架适用场景?
- 82. MyBatis的功能架构是怎样的?
- 83. Mybatis都有哪些Executor执行器?它们之间的区别是什么?
- 84. Mybatis如何执行批量操作?
- 85. 当实体类中的属性名和表中的字段名不一样 ,怎么办?
- 87. Mybatis是否可以映射Enum枚举类?
==Spring
1. Spring的IOC和AOP怎么理解?
- IoC(Inverse of Control:控制反转)是一种设计思想 。这个设计思想就是 将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。
- IoC 最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI)。
- AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
2. Spring AOP里面的几个名词的概念? Spring AOP和AspectJ AOP有什么区别?
(1)连接点(Join point):指程序运行过程中所执行的方法。在Spring AOP中,一个连接点总代表一个方法的执行。
(2)切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。Aspect切面可以看成 Pointcut切点 和 Advice通知 的结合,一个切面可以由多个切点和通知组成。
在Spring AOP中,切面可以在类上使用 @AspectJ 注解来实现。
(3)切点(Pointcut):切点用于定义 要对哪些Join point进行拦截。
切点分为execution方式和annotation方式。execution方式可以用路径表达式指定对哪些方法拦截,比如指定拦截add*、search*。annotation方式可以指定被哪些注解修饰的代码进行拦截。
(4)通知(Advice):指要在连接点(Join Point)上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。通知有各种类型,包括Around、Before、After、After returning、After throwing。
(5)目标对象(Target):包含连接点的对象,也称作被通知(Advice)的对象。 由于Spring AOP是通过动态代理实现的,所以这个对象永远是一个代理对象。
(6)织入(Weaving):通过动态代理,在目标对象(Target)的方法(即连接点Join point)中执行增强逻辑(Advice)的过程。
(7)引入(Introduction):添加额外的方法或者字段到被通知的类。Spring允许引入新的接口(以及对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

- AspectJ 是一个采用Java 实现的AOP框架,它能够对代码进行编译(一般在编译期进行),让代码具有AspectJ 的 AOP 功能,AspectJ 是目前实现 AOP 框架中最成熟,功能最丰富的语言。ApectJ 主要采用的是编译期静态织入的方式。在这个期间使用 AspectJ 的 acj 编译器(类似 javac)把 aspect 类编译成 class 字节码后,在 java 目标类编译时织入,即先编译 aspect 类再编译目标类。
- Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理
3. JDK动态代理和CGLIB动态代理的区别?
1、JDK动态代理具体实现原理:
- 通过实现InvocationHandler接口创建自己的调用处理器;
- 通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
- 通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;
- JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。
2、CGLib动态代理:
- 利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
3、两者对比:
- JDK动态代理是面向接口的。
- CGLib动态代理是通过字节码底层继承要代理类来实现,因此如果被代理类被final关键字所修饰,会失败。
4. Spring通知(Advice)有哪些类型?
- 前置通知(Before Advice): 在目标方法被调用前调用通知功能;相关的类org.springframework.aop.MethodBeforeAdvice
- 后置通知(After Advice): 在目标方法被调用之后调用通知功能;相关的类org.springframework.aop.AfterReturningAdvice
- 返回通知(After-returning): 在目标方法成功执行之后调用通知功能;
- 异常通知(After-throwing): 在目标方法抛出异常之后调用通知功能;相关的类org.springframework.aop.ThrowsAdvice
- 环绕通知(Around): 把整个目标方法包裹起来,在被调用前和调用之后分别调用通知功能相关的类org.aopalliance.intercept.MethodInterceptor
5. Spring中bean的作用域有哪些,有什么区别?
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
- session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
- global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了

6. Spring 中的单例 bean 的线程安全问题了解吗?
单例Bean
- 对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。
如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,无状态的 Bean 不能保存数据,因此是线程安全的。
对于有状态的bean,Spring官方提供的bean,一般提供了通过ThreadLocal去解决线程安全的方法,比如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等。
原型Bean
- 对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。
常见的有 2 种解决办法:
- 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。
- 改变 Bean 的作用域为 “prototype”:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题
Spring如何处理线程并发问题?
-
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
-
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
-
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
7. @Component 和 @Bean 的区别是什么?
- 作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。
- @Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。
- @Bean 注解比 Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。
8. Spring 中的 bean 生命周期?你能重载什么方法吗?

-
Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
-
Bean实例化后对将Bean的引入和值注入到Bean的属性中
-
如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
-
如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
-
如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
-
如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
-
如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
-
如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
-
此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
-
如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
- bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)
9. 将一个类声明为Spring的bean的注解有哪些?
- @Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用@Component 注解标注。
@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
@Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。
10. 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的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
11. Spring bean是什么?
- Spring bean是Spring框架在运行时管理的对象。Spring bean是任何Spring应用程序的基本构建块。你编写的大多数应用程序逻辑代码都将放在Spring bean中。
12. IOC容器中用什么数据结构保存加载的bean对象?
- Map
13. SpringIOC容器的启动流程?

-
初始化 ApplicationContext,环境属性的初始化和验证,启动时间记录和相关标记设置,应用事件和监听者的初始化。
-
准备好容器中的 BeanDefinition (eager-initializing beans),对 BeanDefinition 的解析、扫描和注册,BeanDefinition 的扫描和注册大致可以分为 XML 和注解两种,两种方式各自使用的组件有所不同,该步骤的时间也可以在最前面。
-
初始化 BeanFactory,准备好 BeanFactory 以供 ApplicationContext 进行使用,对接下来将要使用到的 Bean 进行实例化,资源进行准备,属性进行设置。
-
注册 BeanPostProcessors,BeanPostProcessors 是进行扩展的关键组件,需要在该步骤中进行注册,可分为两种类型: 一种是框架使用者提供的,用于特定业务功能的,另一种是框架开发者提供的,用于扩展框架功能。
-
调用 BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor 是一种功能增强,可以在这个步骤添加新的 BeanDefinition 到 BeanFactory 中。
-
调用 BeanFactoryPostProcessor,BeanFactoryPostProcessor 是一种功能增强,可以在这个步骤对已经完成初始化的 BeanFactory 进行属性覆盖,或是修改已经注册到 BeanFactory 的 BeanDefinition。
-
初始化 MessageSource 和 ApplicationEventMulticaster,MessageSource 用于处理国际化资源,ApplicationEventMulticaster 是应用事件广播器,用于分发应用事件给监听者。
-
初始化其他 Bean 和进行其他的的上下文初始化,主要用于扩展
-
注册 ApplicationListene, 将 ApplicationListene 注册到 BeanFactory 中,以便后续的事件分发
-
实例化剩余的 Bean 单例,步骤 4 到 9 都对一些特殊的 Bean 进行了实例化,这里需要对所有剩余的单例 Bean 进行实例化
-
启动完成,资源回收,分发"刷新完成"事件。
14. 什么是 Spring 框架? 列举一些重要的Spring模块?
-
Spring 是一种轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性。
-
Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。
-
Spring Aspects : 该模块为与AspectJ的集成提供支持。
-
Spring AOP :提供了面向切面的编程实现。
-
Spring JDBC : Java数据库连接。
-
Spring JMS :Java消息服务。
-
Spring ORM : 用于支持Hibernate等ORM工具。
-
Spring Web : 为创建Web应用程序提供支持。
-
Spring Test : 提供了对 JUnit 和 TestNG 测试的支持。
15. Spring 事务中哪几种事务传播行为?

支持当前事务的情况:
- TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)
不支持当前事务的情况:
- TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
其他情况:
- TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

16. Spring事务的实现方式和实现原理?你能重载什么方法吗?
- Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。Spring只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过binlog或者undo log实现的。Spring会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别,由此保持一致。
Spring事务的种类:
-
spring支持编程式事务管理和声明式事务管理两种方式:
-
①编程式事务管理使用TransactionTemplate。
-
②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前启动一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
-
声明式事务又分为两种:
-
基于XML的声明式事务
-
基于注解的声明式事务
17. @Transactional(rollbackFor = Exception.class)注解了解吗?
-
我们知道:Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。
-
当@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
-
在@Transactional注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。
18. 解决Spring事务异常回滚,捕获异常不抛出就不会回滚 ?
- 默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚。
- Spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过配置来捕获特定的异常并回滚
- 换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚
解决方案:
- 方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理
- 方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常(现在项目的做法)
- 还有一种方法,而且是推荐方法:在这个代码所在的方法上加上rollbackFor ,
形如:@Transactional(readOnly = true, rollbackFor = Exception.class)。这样也可以回滚。
19. Spring项目启动的时候会加载哪些资源,顺序是怎么样的?
20. Spring中BeanFactory、FactoryBean和ApplicationContext的区别?
BeanFactory和FactoryBean的区别
-
BeanFactory是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范,
-
FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类.
-
区别:BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和装饰者模式类似
-
FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。
BeanFactory和ApplicationContext的区别
- BeanFactory和ApplicationContext就是spring框架的两个IOC容器,现在一般使用ApplicationnContext,不但包含了BeanFactory的作用,同时还进行更多的扩展。
- ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能: MessageSource, 提供国际化的消息访问 ,资源访问,如URL和文件 ,事件传播 ,载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
21. Spring如何解决循环依赖问题的过程?(三级缓存)
- 调用doGetBean()方法,想要获取beanA,于是调用getSingleton()方法从缓存中查找beanA
- 在getSingleton()方法中,从一级缓存中查找,没有,返回null
- doGetBean()方法中获取到的beanA为null,于是走对应的处理逻辑,调用getSingleton()的重载方法(参数为ObjectFactory的)
- 在getSingleton()方法中,先将beanA_name添加到一个集合中,用于标记该bean正在创建中。然后回调匿名内部类的creatBean方法
- 进入AbstractAutowireCapableBeanFactory#ndoCreateBean,先反射调用构造器创建出beanA的实例,然后判断:是否为单例、是否允许提前暴露引用(对于单例一般为true)、是否正在创建中(即是否在第四步的集合中)。判断为true则将beanA添加到【三级缓存】中
- 对beanA进行属性填充,此时检测到beanA依赖于beanB,于是开始查找beanB
- 调用doGetBean()方法,和上面beanA的过程一样,到缓存中查找beanB,没有则创建,然后给beanB填充属性
- 此时 beanB依赖于beanA,调用getSingleton()获取beanA,依次从一级、二级、三级缓存中找,此时从三级缓存中获取到beanA的创建工厂,通过创建工厂获取到singletonObject,此时这个singletonObject指向的就是上 面在doCreateBean()方法中实例化的beanA
- 这样beanB就获取到了beanA的依赖,于是beanB顺利完成实例化,并将beanA从三级缓存移动到二级缓存中
- 随后beanA继续他的属性填充工作,此时也获取到了beanB,beanA也随之完成了创建,回到getsingleton()方法中继续向下执行,将beanA从二级缓存移动到一级缓存中
22. Spring基于xml注入bean的几种方式?
(1)Set方法注入;
(2)构造器注入:①通过index设置参数的位置;②通过type设置参数类型;
(3)静态工厂注入;
(4)实例工厂;
23. Spring 框架中用到了哪些设计模式?
- 工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
- 代理设计模式 : Spring AOP 功能的实现。
- 单例设计模式 : Spring 中的 Bean 默认都是单例的。
- 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
- 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
- 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
24. Spring的自动装配(基于xml配置/基于注解)?
在Spring框架xml配置中共有5种自动装配:

(1)no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。
(2)byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
(3)byType:通过参数的数据类型进行自动装配。
(4)constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
(5)autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
使用注解自动装配
- @Autowired注解可以用在任何方法上,不一定非得是setter方法,只要方法有需要自动装配的参数都可以,但是一般都是使用在setter方法和构造器上的。@Autowired注解默认使用的是byType的方式向Bean里面注入相应的Bean。
- @Resource也可用于自动装配。但@Resource并不是Spring的注解,他的包是javax.annotation.Resource。Spring支持该注解的注入,@Resource通过设置可以按byName和byType 方式注入,如果都没有写,默认按byName方式。
25. 什么是Spring中的依赖注入?依赖注入的基本原则?
26. Spring aop,什么时候会失效?
27. Spring的优缺点是什么?
Spring的优点
- 降低了组件之间的耦合性,实现了软件各层之间的解耦.
- 可以使用容器提供的众多服务,如事务管理,消息服务等.
- 容器提供单利模式支持.
- 容器提供了AOP技术,利用它可以很容易实现的一些拦截,如权限拦截,运行期监控等.
- 容器提供了AOP技术,利用它可以很容易实现运行拦截,如权限拦截,运行期监控等.
- spring对于主流的应用框架提供了很好的支持,例如mybatis等.
- spring属于低入侵设计
- 独立各种应用服务器
- spring的DI机制减低了业务对象替换的复杂性.
- spring的高开放性,并不强制应用于完全依赖于它,开发者可以自由选择spring的部分或者全部.
Spring的缺点
- 使用了大量的反射机制,反射机制非常占用内存。
28. Spring框架中有哪些不同类型的事件?
Spring 提供了以下5种标准的事件:
-
(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
-
(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
-
(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
-
(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
-
(5)请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。
-
如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。
29. 在 Spring中如何注入一个java集合?
30. @Component, @Controller, @Repository, @Service 有何区别?
31. @Autowired和@Resource之间的区别?
-
(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
-
(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
32. @Qualifier 注解有什么作用?
- 如果在容器中出现了两个适合的bean,就会出错。怎么解决呢?这个时候可以使用@Qualifier注解指定一个Bean来装配,这样就不会报异常了。@Qualifier注解采用的是byName的方式。
SpringMVC
33. 说一下 springmvc的执行流程 ?
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用处理器映射器HandlerMapping。
- 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
- DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
- 执行处理器Handler(Controller,也叫页面控制器)。
- Handler执行完成返回ModelAndView
- HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
- DispatcherServlet响应用户。
34. 什么是Spring MVC?简单介绍下你对Spring MVC的理解?
- Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把模型-视图-控制器分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
35. @RequestMapping 的作用是什么?
- @RequestMapping是一个用来处理请求地址映射的注解,可用于类或者方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
36. spring mvc 有哪些组件?
- 前端控制器(DispatcherServlet)
- 处理器映射器(HandlerMapping)
- 处理器适配器(HandlerAdapter)
- 拦截器(HandlerInterceptor)
- 语言环境处理器(LocaleResolver)
- 主题解析器(ThemeResolver)
- 视图解析器(ViewResolver)
- 文件上传处理器(MultipartResolver)
- 异常处理器(HandlerExceptionResolver)
- 数据转换(DataBinder)
- 消息转换器(HttpMessageConverter)
- 请求转视图翻译器(RequestToViewNameTranslator)
- 页面跳转参数管理器(FlashMapManager)
- 处理程序执行链(HandlerExecutionChain)
37. SpringMVC 常用注解都有哪些?
Spring2.5引入注解式处理器
- @Controller:用于标识是处理器类;
- @RequestMapping:请求到处理器功能方法的映射规则;
- @RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;
- @ModelAttribute:请求参数到命令对象的绑定;
- @SessionAttributes:用于声明session级别存储的属性,放置在处理器类上,通常列出模型属性(如@ModelAttribute)对应的名称,则这些属性会透明的保存到session中;
- @InitBinder:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;
Spring3.0引入RESTful架构风格支持,又引入了更多的注解支持
- @CookieValue:cookie数据到处理器功能处理方法的方法参数上的绑定;
- @RequestHeader:请求头(header)数据到处理器功能处理方法的方法参数上的绑定;
- @RequestBody:请求的body体的绑定(通过HttpMessageConverter进行类型转换);
- @ResponseBody:处理器功能处理方法的返回值作为响应体(通过HttpMessageConverter进行类型转换);
- @ResponseStatus:定义处理器功能处理方法/异常处理器返回的状态码和原因;
- @ExceptionHandler:注解式声明异常处理器;
- @PathVariable:请求URI中的模板变量部分到处理器功能处理方法的方法参数上的绑定
- 如何解决 get 和 post 乱码问题?
- SpringMVC怎么样设置重定向和转发?
40. Spring MVC的优点?
-
可以支持各种视图技术,而不仅仅局限于JSP;
-
与Spring框架集成(如IoC容器、AOP等);
-
清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。
-
支持各种请求资源的映射策略。
41. 什么是DispatcherServlet?
- DispatcherServlet是前端控制器设计模式的实现,提供了Spring Web MVC的集中访问点, 而且负责职责的分派,而且与Spring Ioc容器无缝集成, 从而可以获的Spring的所有好处。
DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
- 文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
- 通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
- 通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
- 通过ViewResolver解析逻辑视图名到具体视图实现;
- 本地化解析;
- 渲染具体的视图等;
- 如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。
42. Spring MVC的控制器是不是单例模式,如果是,有什么问题,怎么解决?
- 在多线程进行访问的时候,有线程安全问题,但是不建议使用同步,因为会影响性能.
解决方案
-
1、不要在controller中定义成员变量。
-
2、万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例模式
成员方法也是共享的,为什么就不会出现问题呢?
- java 里,每个线程都有自己独享的空间,也就是栈内存。线程在调用方法的时候,会创建一个栈帧。
- 也就是说调用一个方法的时候,也就是一个栈帧的入栈过程,该方法执行完毕,栈帧也就出栈了。换句话讲,成员方法对于每个线程事实上是私有的,而不是你表面看上去的那样是 “共享” 的。
那么为什么成员变量会出问题呢?
-
如你所知道的,每个新建对象都存放在堆中,每个持有该对象引用的线程,都可以访问到它(只要你有那个权限)。这也就是说,成员变量对于每个线程,事实上是共享的。
-
在单例模式里,方法是私有的,成员变量是共享的,所以方法是安全的,变量是共享的
43. MVC是什么?MVC设计模式的好处有哪些?
- mvc是一种设计模式(设计模式就是日常开发中编写代码的一种好的方法和经验的总结)。模型(model)-视图(view)-控制器(controller),三层架构的设计模式。用于实现前端页面的展现与后端业务数据处理的分离。
mvc设计模式的好处
- 分层设计,实现了业务系统各个组件之间的解耦,有利于业务系统的可扩展性,可维护性。
有利于系统的并行开发,提升开发效率。
44. Spring MVC的异常处理?
45. Spring MVC里面拦截器是怎么写的?
SpringBoot
46. SpringBoot的事务实现原理?
1.开启事务注解
- 在项目主类上,加上注解@EnableTransactionManagement,例如:
@EnableTransactionManagement
public class MySpringBootService extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(CoreService.class, args);
}
}
在目标类、方法上添加注解@Transactional
- 如果将@Transactional添加到类上,则表示此类的所有方法都开启事务管理。如:
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
@Service
public class MyServiceImpl implements MyService {
//class body
}
- 如果将@Transactional添加到方法上,则表示此方法开启事务管理。如:
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
@Override
public ActivityPo getActivityById(Long id){
//method body
}
- 如果一个方法上存在@Transactional,且其所属类上同样存在@Transactional,则以方法级别的事务配置为准。
@Transactional事务实现机制
-
1.整体事务控制流程
当@Transactional注解的方法被类外部的代码调用时,Spring在运行时为方法所在类生成一个AOP代理对象。代理对象根据@Transactional的属性,决定是否由事务拦截器TransactionInterceptor对此方法进行事务拦截。在进行事务拦截时,会先开启事务,然后执行业务代码,根据执行是否出现异常,通过抽象事务管理器AbstractPlatformTransactionManager来进行rollback或者commit。 -
2.Spring AOP的两种代理
Spring AOP有两种CglibAopProxy和JdkDynamicAopProxy,其中:
CglibAopProxy在其内部类DynamicAdvisedInterceptor的intercept()方法中,判断是否进行事务拦截。JdkDynamicAopProxy在其invoke()方法中,判断是否进行事务拦截。 -
3.事务操作的底层实现
抽象事务管理器AbstractPlatformTransactionManager的rollback和commit都需要具体的实现类进行实现。抽象事务管理器AbstractPlatformTransactionManager的父级接口是PlatformTransactionManager。存在很多事务管理器实现类,例如DataSourceTransactionManager等。不同的事务管理器管理不同的数据资源 DataSource,比如DataSourceTransactionManager管理者JDBC数据源。应确保被调用方法中使用的数据源都加载了事务管理器。
47. Spring Boot、Spring MVC 和 Spring 有什么区别?
-
Spring 就像一个大家族,有众多衍生产品例如 Boot,Security,JPA等等。但他们的基础都是Spring 的 IOC 和 AOP,IOC提供了依赖注入的容器,而AOP解决了面向切面的编程,然后在此两者的基础上实现了其他衍生产品的高级功能;Spring MVC是基于 Servlet 的一个 MVC 框架,主要解决 WEB 开发的问题,因为 Spring 的配置非常复杂,各种xml,properties处理起来比较繁琐。于是为了简化开发者的使用,Spring社区创造性地推出了Spring Boot,它遵循约定优于配置,极大降低了Spring使用门槛,但又不失Spring原本灵活强大的功能
-
Spring MVC和Spring Boot都属于Spring,Spring MVC 是基于Spring的一个 MVC 框架,而Spring Boot 是基于Spring的一套快速开发整合包

48. Spring Boot 自动配置原理是什么?
-
@SpringBootApplication等同于下面三个注解:
-
@SpringBootConfiguration
-
@EnableAutoConfiguration
-
@ComponentScan
-
其中@EnableAutoConfiguration是关键(启用自动配置),内部实际上就去加载META-INF/spring.factories文件的信息,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能!
49. 你如何理解 Spring Boot 中的 Starters?
- Starters可以理解为启动器, Spring Boot中的Starter是一个包含很多依赖描述的集合,只要添加一个Starter,这个Starter里面约定的依赖都会被添加到项目中,例如代码添加了spring-boot-starter-web,执行maven操作就会下载web应用需要的依赖jar。开发者通过使用这些Starter可以快速的搭建开发环境,自动加载所需要的依赖和配置参数属性。

50. 什么是 Spring Boot?
- Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。
51. 为什么要用 Spring Boot?
- 在使用Spring框架进行开发的过程中,需要配置很多Spring框架包的依赖,如spring-core、spring-bean、spring-context等,而这些配置通常都是重复添加的,而且需要做很多框架使用及环境参数的重复配置,如开启注解、配置日志等。Spring Boot致力于弱化这些不必要的操作,提供默认配置,当然这些默认配置是可以按需修改的,快速搭建、开发和运行Spring应用。
52. Spring Boot 的核心配置文件有哪几个?bootstrap.properties 和 application.properties 有何区别 ?
-
单纯做 Spring Boot 开发,可能不太容易遇到 bootstrap.properties 配置文件,但是在结合 Spring Cloud 时,这个配置就会经常遇到了,特别是在需要加载一些远程配置文件的时侯。
-
spring boot 核心的两个配置文件:
-
bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加载的,比 applicaton 优先加载,配置在应用程序上下文的引导阶段生效。一般来说我们在 Spring Cloud Config 或者 Nacos 中会用到它。且 boostrap 里面的属性不能被覆盖;
-
application (. yml 或者 . properties): 由ApplicatonContext 加载,用于 spring boot 项目的自动化配置。
53. Spring Boot 的配置文件有哪几种格式?它们有什么区别?什么是 YAML?
- 主要有.properties 和 .yml格式,它们的区别主要是书写格式不同。另外,.yml 格式不支持 @PropertySource 注解导入配置。
54. Spring Boot 有哪几种读取配置的方式?
- Spring Boot获取文件总的来说有三种方式,分别是@Value注解,@ConfigurationProperties注解和Environment接口。这三种注解可以配合着@PropertySource来使用,@PropertySource主要是用来指定具体的配置文件。
55. Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
-
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:
-
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
-
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
-
@ComponentScan:Spring组件扫描。
- Spring Boot 需要独立的容器运行吗?
- 你如何理解 Spring Boot 配置加载顺序?
- Spring Boot 如何定义多套不同环境配置? 什么是 Spring Profiles?
- Spring Boot 可以兼容老 Spring 项目吗,如何做?
- Spring Boot 2.X 有什么新特性?与 1.X 有什么区别?
61. Spring Boot 有哪些优点?
- 容易上手,提升开发效率,为 Spring 开发提供一个更快、更广泛的入门体验。
- 开箱即用,远离繁琐的配置。
- 提供了一系列大型项目通用的非业务性功能,例如:内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等。
- 没有代码生成,也不需要XML配置。
- 避免大量的 Maven 导入和各种版本冲突。
62. Spring Boot 中如何解决跨域问题 ?
- CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制,如果浏览器支持CORS、并且判断Origin通过的话,就会允许XMLHttpRequest发起跨域请求。
CROS常见header
- Access-Control-Allow-Origin:http://somehost.com 表示允许http://somehost.com发起跨域请求。
- Access-Control-Max-Age:86400 表示在86400秒内不需要再发送预校验请求。
- Access-Control-Allow-Methods: GET,POST,PUT,DELETE 表示允许跨域请求的方法。
- Access-Control-Allow-Headers: content-type 表示允许跨域请求包含content-type
方式1:返回新的CorsFilter
package com.hehe.yyweb.config;
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//放行哪些原始域
config.addAllowedOrigin("*");
//是否发送Cookie信息
config.setAllowCredentials(true);
//放行哪些原始域(请求方式)
config.addAllowedMethod("*");
//放行哪些原始域(头部信息)
config.addAllowedHeader("*");
//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
config.addExposedHeader("*");
//2.添加映射路径
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
方式2:重写WebMvcConfigurer
- 任意配置类,返回一个新的WebMvcConfigurer Bean,并重写其提供的跨域请求处理的接口,目的是添加映射路径和具体的CORS配置信息。
package com.hehe.yyweb.config;
@Configuration
public class GlobalCorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
//重写父类提供的跨域请求处理的接口
public void addCorsMappings(CorsRegistry registry) {
//添加映射路径
registry.addMapping("/**")
//放行哪些原始域
.allowedOrigins("*")
//是否发送Cookie信息
.allowCredentials(true)
//放行哪些原始域(请求方式)
.allowedMethods("GET","POST", "PUT", "DELETE")
//放行哪些原始域(头部信息)
.allowedHeaders("*")
//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
.exposedHeaders("Header1", "Header2");
}
};
}
}
方式3:使用注解(@CrossOrigin)
@RequestMapping("/hello")
@ResponseBody
@CrossOrigin("http://localhost:8080")
public String index( ){
return "Hello World";
}
方式4:手工设置响应头(HttpServletResponse )
@RequestMapping("/hello")
@ResponseBody
public String index(HttpServletResponse response){
response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
return "Hello World";
}
63. spring-boot-starter-parent 有什么用 ?
- spring-boot-starter-parent 是一个特殊的starter,它用来提供相关的Maven默认依赖。使用它之后,常用的包依赖可以省去version标签。
- 指定编码格式默认使用utf-8。
- 指定java版本默认使用1.8。
64. 运行 Spring Boot 有哪几种方式?
- 打包用命令或者放到容器中运行
- 用 Maven/Gradle 插件运行
- 直接执行 main 方法运行
65. 如何使用 Spring Boot 实现异常处理?
- Springboot对于异常的处理也做了不错的支持,它提供了一个 @ControllerAdvice注解以及 @ExceptionHandler注解,前者是用来开启全局的异常捕获,后者则是说明捕获哪些异常,对那些异常进行处理。
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(value =Exception.class)
public String exceptionHandler(Exception e){
System.out.println("发生了一个异常"+e);
return e.getMessage();
}
}
MyBatis
66. MyBatis是什么?
- 首先Mybatis是一个优秀的持久化框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。Mybatis减少了大部分JDBC的代码,避免了手动设置参数和结果集的映射。Mybatis用简单的XML配置文件或注解来配置映射关系,将接口和POJO对象映射到数据库记录中。
67. ORM是什么?
- : 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。
68. 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
- Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。
- 而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。
69. 传统JDBC开发存在的问题?JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?
-
① 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
-
解决:在中心xml文件中配置数据链接池,使用连接池管理数据库链接。
-
② Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
-
解决:将Sql语句配置在xxxmapper.xml文件中与java代码分离。
-
③ 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
-
解决: Mybatis自动将java对象映射至sql语句。
-
④ 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
-
解决:Mybatis自动将sql执行结果映射至java对象。
70. Mybatis优缺点?
优点:
-
与JDBC相比,减少了50%以上的代码量。
-
MyBatis是最简单的持久化框架,小巧并且简单易学。
-
MyBatis灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,可重用。
-
提供XML标签,支持编写动态SQL语句(XML中使用if, else)。
-
提供映射标签,支持对象与数据库的ORM字段关系映射(在XML中配置映射关系,也可以使用注解)。
缺点:
-
SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写SQL语句的功底有一定要求。
-
SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
71. MyBatis编程步骤是什么样的?
-
1、创建SqlSessionFactory 会话工厂
-
2、通过SqlSessionFactory 创建SqlSession
-
3、通过sqlsession执行数据库操作
-
4、调用session.commit()提交事务
-
5、调用session.close()关闭会话
72. 请说说MyBatis的工作原理?
- 1)读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。
- 2)加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。
mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。 - 3)构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
- 4)创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。
- 5)Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
- 6)MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,
用于存储要映射的 SQL 语句的 id、参数等信息。 - 7)输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。
输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。 - 8)输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程
73. 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()方法的调用。
-
这就是延迟加载的基本原理。
-
当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的
74. #{}和${}的区别?
-
1)#{}是预编译处理,$ {}是字符串替换。
-
2)mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;mybatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。
-
3)使用 #{} 可以有效的防止SQL注入,提高系统安全性。
75. 什么是MyBatis的接口绑定?有哪些实现方式?
- 一种是通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;
- 另外一种就是通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。
76. 使用MyBatis的mapper接口调用时有哪些要求?
-
1、Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同;
-
2、Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的
parameterType 的类型相同; -
3、Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的
resultType 的类型相同; -
4、Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径。
77. Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?
- 动态sql是指在进行sql操作的时候,传入的参数对象或者参数值,根据匹配的条件,有可能需要动态的去判断是否为空,循环,拼接等情况;
- if , where 标签,include标签,choose、when、otherwise 标签,foreach 标签,map参数,set标签,trim标签,prefix(前缀),prefixOverrides(去掉第一个标记),suffix(后缀),suffixOverrides(去掉最后一个标记)
动态sql的执行原理
- 首先在解析xml配置文件的时候,会有一个SqlSource sqlSource =langDriver.createSqlSource(configuration, context, parameterTypeClass) 的操作
- createSqlSource底层使用了XMLScriptBuilder来对xml中的标签进行解析
- XMLScriptBuilder调用了parseScriptNode()的方法,
- 在parseScriptNode()的方法中有一个parseDynamicTags()方法,会对nodeHandlers里的标签根据不同的handler来处理不同的标签
- 然后把DynamicContext结果放回SqlSource中
- DynamicSqlSource获取BoundSql
- 在Executor执行的时候,调用DynamicSqlSource的解析方法,并返回解析好的BoundSql,和已经排好序,需要替换的参数

78. Mybatis是如何进行分页的?分页插件的原理是什么?
-
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
-
分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义分页插件。在插件的拦截方法内,拦截待执行的 SQL ,然后重写 SQL ,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。
-
举例:SELECT * FROM t_user,拦截 SQL 后重写为:select * FROM student LIMIT 0,10 。
79. 缓存Mybatis的一级、二级缓存?
-
首先用户第一次查询sql时候,sql的查询结果就会被写入sqlsession一级缓存中的,这样用户第二次查询时,直接从一级缓存取出数据,而不是数据库。
-
如果用户出现commit操作时,比如增删改查,这时sqlsession中一级缓存区域就会全部清空。清空之后再次去一级缓存查找不到,就会走数据库进行查找,然后再次存到缓存中。注意:缓存使用的数据结构也是map的。

- 二级缓存的范围就是mapper级别,也就是mapper以命名空间为单位创建缓存数据结构,也是map结构。二级缓存和 一级缓存一样的是,二级缓存的多个sqlsession去操作同一个mapper映射的sql语句,然后多个sqlsession可以共用二级缓存这样的一个思想,它是跨sqlsession的。

80. Hibernate 和 MyBatis 的区别?
-
1、hibernate真正掌握要比mybatis难,因为hibernate的功能和特性非常多,还不适合多表关联查询。
-
2、hibernate查询会将所有关联表的字段全部查询出来,会导致性能消耗,当然hibernate也可以自己写sql指定字段,但这就破坏了hibernate的简洁性。mybatis的sql是自己手动编写的,所以可以指定查询字段。
-
3、hibernate与数据库管联只需在xml文件中配置即可,所有的HQL语句都与具体使用的数据库无关,移植性很好;mybatis所有的sql都是依赖所用数据库的,所以移植性差。
-
4、hibernate是在jdbc上进行一次封装,mybatis是基于原生的jdbc,运行速度较快。
-
5、如果有上千万的表或者单次查询或提交百万数据以上不建议使用hibernate。如果统计功能、多表关联查询较多较复杂建议使用mybatis。
81. MyBatis框架适用场景?
-
MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。
-
对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。
82. MyBatis的功能架构是怎样的?

- API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
- 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
- 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
83. Mybatis都有哪些Executor执行器?它们之间的区别是什么?
Mybatis有三种基本的Executor执行器: SimpleExecutor、ReuseExecutor、BatchExecutor。
-
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
-
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
-
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
-
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。
-
Mybatis中如何指定使用哪一种Executor执行器?
-
答:在Mybatis配置文件中,可以指定默认的ExecutorType执行器类型,也可以手动给DefaultSqlSessionFactory的创建SqlSession的方法传递ExecutorType类型参数。
84. Mybatis如何执行批量操作?
- 首先,创建一个简单的insert语句:
<insert id=”insertname”>
insert into names (name) values (#{value})
</insert>
- 然后在java代码中像下面这样执行批处理插入:
list<string> names = new arraylist();
names.add(“fred”);
names.add(“barney”);
names.add(“betty”);
names.add(“wilma”);
// 注意这里 executortype.batch
sqlsession sqlsession = sqlsessionfactory.opensession(executortype.batch);
try {
namemapper mapper = sqlsession.getmapper(namemapper.class);
for (string name : names) {
mapper.insertname(name);
}
sqlsession.commit();
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
throw e;
}
finally {
sqlsession.close();
}
85. 当实体类中的属性名和表中的字段名不一样 ,怎么办?
-
第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。

-
第2种: 通过来映射字段名和实体类属性名的一一对应的关系

87. Mybatis是否可以映射Enum枚举类?
-
mybatis自带枚举类型转换器MyBatis内置了两个枚举转换器分是:org.apache.ibatis.type.EnumTypeHandler和org.apache.ibatis.type.EnumOrdinalTypeHandler。
-
EnumTypeHandler这是默认的枚举转换器,该转换器将枚举实例转换为实例名称的字符串,即将UserSex.MALE转换MALE。
-
EnumOrdinalTypeHandler顾名思义这个转换器将枚举实例的ordinal属性作为取值,即UserSex.MALE转换为0,UserSex.FEMALE转换为1。
-
第一种方式:指定哪个类使用我们自己编写转换器进行转换,在MyBatis配置文件中配置如下:
<typeHandlers>
<typeHandler handler="com.xizi.typeHandler.EnumOrderStatusHandler " javaType="com.example.xizi.enums.OrderStatusEnum"/>
</typeHandlers>
- 第二种方式:修改指定xml文件,指定的Mapper生效
<result column="status" property="orderStatusEnum"
typeHandler="com.xizi.typeHandler.EnumOrderStatusHandler"/>
<insert id="insert" parameterType="com.xizi.entity.OrderInfo">
INSERT INTO
order_test
(status)
VALUES (
#{orderStatusEnum, typeHandler=com.example.typeHandler.EnumOrderStatusHandler, jdbcType=INTEGER}
)
</insert>

406

被折叠的 条评论
为什么被折叠?



