Spring框架 - Spring

29 阅读9分钟

前言

22题。

谈谈你对Spring IOC的理解?

本质上就是控制反转,是一种解耦,就是将对象的控制权由程序员手中反转到Spring手中。

Spring也会自动完成依赖注入以及创建所需的对象。

经常使用并且属性不变的对象放在IOC容器中(controllerservice)。

Spring中有哪些依赖注入方式?

主要包括两种方式:构造器依赖注入和Setter方法注入。

你用过哪些Spring注解?(高频)

我们常用的Spring注解主要分为下面几大类:

  1. 创建对象@Component@Controller@Service@Repository

  2. 依赖注入@Autowired@Qualifier@Resource

  3. 配置类@Configuration@Bean

  4. 其他:声明注解扫描的@ComponentScan,声明Bean的作用域的@Scope,用于切面编程的@Around@Pointcut等等。

SpringBean的作用域有几种?

常见的有:

  1. 单例:对象随Spring容器创建而创建,跟随Spring容器销毁而销毁,无论获取多少次得到的都是同一个对象,这也是默认作用域。

  2. 多例:每次获取的时候才会创建,而且每次获取到的都不一样。

还有三种分别是requestsessionapplication

Spring中的bean线程安全吗?

Spring中的Bean主要分为单例和多例:

  1. 多例对象每次获取都会创建新实例,也就是说线程之间不存在Bean共享问题,也就不存在线程安全问题;

  2. 单例对象是所有线程共享一个实例,因此就可能会存在线程安全问题。但是单例对象又分为无状态和有状态,无状态指只查询不会修改,因此不存在线程安全问题,有状态需要进行修改,因此就可能存在线程安全问题,所以只有有状态的单例Bean才会存在线程安全问题。

有两种方法来处理:

  1. Bean的作用域由单例改为多例;

  2. 将可变的变量存在ThreadLocal中, 有线程隔离的特性,每个线程只需要操作自己的,从而解决线程安全问题。

谈谈你对SpringAOP的理解?

AOP,又叫面向切面编程,就是将那些共用的封装起来,然后再动态插入到业务中。可以减少重复代码,降低耦合,并有利于扩展和维护。

AOP基于动态代理,支持JDKCGLIB的代理方式,并且会根据被代理类是否有接口自动选择最合适的代理方式。

主要使用场景有:事务管理、日志(操作记录)、性能监视、安全检查。

AOP的代理有几种方式?

有两种:

  1. JDK动态代理模式:只能对有接口的类进行代理,而且效率较高;

  2. CGLIB代理模式:可以对任意的类进行动态代理,但是效率上不如JDK

总的来说,如果被代理类有接口,就用JDK;如果没有接口,就用CGLIB

SpringAOP的通知类型有哪些?

五种类型的通知:

  1. 前置通知:在某切点之前执行的通知;

  2. 返回后通知:在某切点正常完成后执行的通知;

  3. 抛出异常后通知:在某切点抛出异常退出时执行的通知;

  4. 后置通知:在某切点退出的时候执行的通知(不论是正常返回还是异常退出);

  5. 环绕通知:包围一个切点的通知(一个可以包含那四个通知)。

了解Spring的事务管理吗?

Spring支持编程式事务和声明式事务。

  1. 编程式事务:使用try-catch捕获异常,配合事务的api来手动处理事务问题。这种方式的缺点是代码耦合,复用性低,优点是可以精确控制要增强的代码;

  2. 声明式事务:基于AOP,将业务方法作为切点,将事务处理方法作为增强,通过动态代理实现事务的管理。它的优点是降低代码耦合,复用性高。目前在企业中基本上都是采用声明式事务的。

Spring事务传播行为有几种?

7种:

  1. 必须事务:默认必须有事务,有就加入,没有就新建;

  2. 必须新事务:必须有新事务,有就新建,没有也新建;

  3. 强制事务:有就加入,没有就抛出异常;

  4. 强制无事务:有就抛出异常;

  5. 支持事务:有就加入该事务,没有就继续运行;

  6. 不支持事务:有就挂起,没有就继续运行;

  7. 嵌套事务:外层失败内层回滚,内层失败外层正常运行。

Spring中的事务是如何实现的?

Spring事务底层是基于数据库事务和AOP机制的,使用了一个注解@Transactional,如果执行sql没有异常就提交,有异常就回滚。

@Transactional控制事务的原理?

@Transactional注解控制事务原理上是基于AOP来实现的:

  1. 先从连接池中获取connection再把事务改成手动提交(mysql事务是自动提交的),获取到的connection会放入到ThreadLocal中;

  2. 整个方法执行完有问题rollback,没有问题再commit提交(保证这个方法中共用的是同一个connection);

  3. connection改为自动提交后再还回连接池中,并把ThreadLocal中的connection移除掉。

如果是分布式事务,就会涉及多个数据源,此时不能再用ThreadLocal,而是要用一个事务调节器:Seata,让Seata管理从多个数据源来的connection

@Transactional注解有哪些参数?

共有9个参数,分别为:

  1. isolation 事务隔离级别,默认为DEFAULT
  2. propagation 事务传播机制,默认为REQUIRED
  3. readOnly 事务读写性,默认为false
  4. noRollbackFor 一组异常类,遇到时不回滚,默认为{}
  5. noRollbackForClassName 一组异常类名,遇到时不回滚,默认为{}
  6. rollbackFor 一组异常类,遇到时回滚,默认为{}
  7. rollbackForClassName 一组异常类名,遇到时回滚,默认为{}
  8. timeout 超时时间,以秒为单位
  9. value 可选的限定描述符,指定使用的事务管理器,默认为“”

Spring中的设计模式有哪些?

  1. 工厂模式:创建bean对象;

  2. 单例模式bean对象默认都是单例的;

  3. 代理模式AOP功能用到了JDKCGLIB的动态代理方式;

  4. 模板方法模式:用来解决代码重复的问题。比如RestTemplate

  5. 观察者模式spring的事件监听器ApplicationLisener

Spring是怎么解决循环依赖的?

循环依赖简单来说就是a依赖bb依赖aab之间相互注入,导致它们之间形成了一个闭环,无法继续执行下去的情况。

解决循环依赖利用了三级缓存:

  • 一级缓存:放已经初始化完成的实例

  • 二级缓存:放未初始化完成的实例

  • 三级缓存:放用来创建对象的工厂(ObjectFactory

如果加了@Async会报错,因为它也会产生一个对象,所以a或者b上加@Lazy

SpringBean的生命周期?

主要由五个部分构成:

  1. 构造Bean对象:相当于new对象;

  2. 设置Bean属性:给属性赋值;

  3. 初始化回调:加上@PostConstruct的方法称为初始化方法,有就执行,没有就不执行;

  4. Bean调用:进行调用,要用对象的话从ConcurrentHashMap中取值,要是需要被代理,用AOP生成代理对象,最终生成的Bean存到单例池中;

  5. 销毁Bean:在容器关闭之后销毁Bean加上@PreDestroy

SpringMVC的执行流程?

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

具体流程如下所示:

  1. 用户发送出请求到【前端控制器DispatcherServlet】;

  2. 【前端控制器DispatcherServlet】收到请求调用【处理器映射器HandlerMapping】;

  3. 【处理器映射器HandlerMapping】找到具体的处理器(可查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给【前端控制器DispatcherServlet】;

  4. 【前端控制器DispatcherServlet】调用【处理器适配器HandlerAdapter】;

  5. 【处理器适配器HandlerAdapter】经过适配调用具体的处理器(Handler/Controller);

  6. Controller执行完成返回ModelAndView对象;

  7. 【处理器适配器HandlerAdapter】将Controller执行结果ModelAndView返回给【前端控制器DispatcherServlet】;

  8. 【前端控制器DispatcherServlet】将ModelAndView传给【视图解析器ViewReslover】;

  9. 视图解析器ViewReslover解析后返回具体View(视图);

  10. 【前端控制器DispatcherServlet】根据View渲染视图(即将模型数据填充至视图中);

  11. 【前端控制器DispatcherServlet】响应用户。

SpringMVC的常用注解有哪些?

  1. 声明Bean到Springmvc容器@RestController=@Controller+@ResponseBody,将返回的集合或对象转换为JSON

  2. 设置请求路径:通用的@RequestMapping@GetMapping@PostMapping@PutMapping@DeleteMapping

  3. 接收请求参数:

  • @RequestBody: 接收请求体中的json数据;
  • @PathVariable:接收请求路径中的参数;
  • @RequestHeader:接收请求头中的参数;
  • @RequestParam:一般用于给参数设置默认值或者完成请求参数和controller方法参数的映射。(指的是接受如http://127.0.0.1/query?name=111&age=12这样的请求中的nameage这样的参数

@Autowired与@Resource区别?

  1. 来源不同@Autowiredspring提供的注解,@ResourceJDK提供的注解;
  2. 默认注入方式不同@Autowired默认的注入方式是ByType(根据类型进行匹配),@Resource默认的注入方式是ByName (根据名称进行匹配);
  3. 按名称查找bean的方式不同@Autowired可以通过@Qualifier来显示指定的名称,@Resource可以通过name来显示指定名称。

Spring框架如何对bean在实例化之后做特殊处理?

实现BeanPostProcessor接口来对bean进行特殊处理。BeanPostProcessor接口提供了两个方法:postProcessBeforeInitializationpostProcessAfterInitialization。这两个方法会在bean的初始化方法(如果有的话,比如@PostConstruct注解标注的方法)执行前后被调用。

Spring中,loC容器配置方式有哪几种?

  1. XML配置
  2. 注解配置
  3. Java代码配置

Spring事务隔离级别包括?

Spring事务隔离级别比数据库事务隔离级别多一个default,这里的default指的是使用底层数据库默认的隔离级别,如MySQL默认是可重复读,PostgreSQL默认是读已提交。

此外,在进行配置的时候,如果数据库和spring代码中的隔离级别不同,那么以spring的配置为主。