文章目录
Spring中的单例bean是线程安全的吗
不是线程安全的。在并发执行请求的情况下,如果该请求的业务逻辑中存在对单例bean的修改、成员变量的修改,则要考虑线程安全问题,而且Spring并没有提供bean的线程安全策略。在Spring中可以使用@Scope注解来指定bean的生命周期,模式有singleton、prototype、request、session、global session,第一种指定的是单例bean、第二种指定的是多例bean,默认是单例bean。在Spring中的bean大多数是被注入无状态的对象,没有线程安全问题,如果定义了可修改的成员变量,是要考虑线程安全问题的,可以使用多例bean、加锁、ThreadLocal来解决部分问题,最后,尽量不要在bean中定义成员变量。
什么是AOP,项目中有没有使用到AOP
AOP称为面向切面编程,用于那些与业务无关的,却和多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被称为"切面(Aspect)",减少系统中的重复代码,降低模块之间的耦合度,同时提高了系统的可维护性,常见的使用场景有:记录操作记录、缓存处理、Spring中内置的事务处理(编程式事务、声明式事务)、公共字段的填充等等。
Spring中的事务是如何实现的
本质是通过事务管理器 + 动态代理,对加了@Transaction注解的方法前后进行封装,事务拦截器来拦截方法调用,在执行方法之前开启事务,在执行目标方法后根据执行情况提交或回滚事务,受到AOP支持。
Spring中事务失效的场景有哪些
- 异常捕获处理 :事务通知只有捕获目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理了异常,事务后续的回滚则不进行,导致事务失效,在这种情况下,如果希望事务不失效,那我们应该让事务感知到异常,所以我们在catch块中添加抛出异常即可,
throw new RuntimeException(e)
。 - 抛出检查异常(checked exceptions) :Spring默认只会回滚非检查异常,在这种情况下我们希望事务不失效,可以指定检查的异常为所有异常,这样只要是异常,事务都会生效,
@Transactional(rollbackFor = Exception.class)
。 - 非public方法导致的事务失效:因为Spring为方法创建代理、添加事务通知,前提条件都是该方法是public的,所以希望在这种情况下事务不失效,把方法改为public的即可。
Bean的生命周期
- 手写Spring中Bean的生命周期:https://github.com/openallzzz/spring-openallzzz
- 调用BeanDefinition获取bean的定义信息(获取beanDefinition的class信息)
- 调用构造函数实例化bean(反射调用:
clazz.getDeclaredConstructor().newInstance()
) - bean的依赖注入(反射获取属性,判断属性是否存在注解
@Autowired
) - 处理aware接口(
BeanNameAware、BeanFactoryAware、ApplicationContextAware
) - Bean的后置处理器BeanPostProcessor-前置(postProcessBeforeInitialization)
- 初始化方法(重写InitializingBean中的afterPropertiesSet方法、init-method)
- Bean的后置处理器BeanPostProcessor-后置(postProcessAfterInitialization)
- 销毁bean
Spring中的循环依赖(循环引用)
就是两个或两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于A。
循环依赖在spring中是允许存在的,spring框架依据三级缓存已经解决了大部分的循环依赖(非构造方法产生的)
- 一级缓存:单例池,缓存已经经历了完整的生命周期,已经被初始化完成的bean对象
- 二级缓存:缓存早期的bean对象(生命周期还没走完)
- 三级缓存:缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的
构造方法出现了循环依赖的解决方案,spring框架并不能解决构造函数的循环依赖,我们可以使用@Lazy注解进行懒加载,什么时候需要对象再进行bean对象的创建。
SpringMVC的执行流程
-
视图阶段(JSP、Thymeleaf):
-
前后端分离阶段(接口开发、异步):
SpringBoot自动配置原理
Spring、SpringMVC、SpringBoot常见注解
- Spring
- SpringMVC
- SpringBoot
MyBatis执行流程
MyBatis是否支持延迟加载
支持延迟加载,但默认是关闭的。对于延迟加载的定义,这里举一个例子,用户实体中存在订单属性,如果我们在查询用户的时候,把用户所属的订单数也查询出来,这个就是立即加载;如果在查询用户的时候,暂时不查询订单数据,当需要订单数据的时候,再查询订单,这个就是延迟加载。
延迟加载的原理
MyBatis的一级、二级缓存
注意开启二级缓存需要在配置文件中开启cacheEnabled=true,并且在相应的mapper.xml文件中使用<cache/>
标签,相关select语句的参数 useCache=true,相关的实体类需要实现序列化接口,数据才会被加入到二级缓存。
MyBatis的二级缓存什么时候会清理缓存中的数据
详细解答:https://blog.csdn.net/jinbaizhe/article/details/81158514
当某一个作用域(一级缓存Session / 二级缓存namespace)进行了写操作(新增、修改、删除)操作,默认该作用域下所有select中的缓存将被清空。