1.Bean的作用范围
1.prototype:为每一个bean请求单独创建一个
2.singleton:单例,默认实现,由BeanFactory管理
3.request:为每一个网络请求单独创建一个实例
4.session:为每一个会话创建一个实例,和request差不多
5.application:为每一个web应用创建一个实例
6.websocket:为每一个websocket应用创建一个实例
2.Bean的生命周期
1.实例化
2.属性赋值(依赖注入)
3.初始化
(1)Aware:实现了Aware接口的方法会被Spring调用,主要用来获取Spring容器的上下文信息
(2)BeanPostProcessor的before方法:常用于AOP
(3)InitialBean的afterSetProperties
(4)xml配置的init-method 等同于@PostConstruct标注的方法
(5)BeanPostProcessor的after方法
4.销毁
2.事务的传播行为
@Transactional(rollbackfor = Expection.class,propagetion = Propagation.REQUIRED)
rollbackfor可以指定事务回滚的条件,默认是RuntimeExpection才会回滚,碰到编译异常就不会。
propagation是事务的传播行为,指一个事务方法被另一个事务方法调用时应该如何控制事务。
1.REQUIRED,Spring事务默认属性,会检查调用者是否开启事务,有则加入,没有则新建一个事务
2.REQUIRED_NEW,不管啊有没有别的事务,总会开启一个新的事物
3.SUPPORTS,如果调用者开启事务,则加入该事务,没有则不开启事务
4.NOT_SUPPORTED,不支持事务,在无事务状态下运行,如果调用者有事务,则将该事物挂起,执行完自己的代码后再恢复
5.NEVER,必须没有事务,否则抛异常
6.MANDATORY,必须有事务,否则抛异常
3.事务的隔离级别
在数据库执行并发事务时会出现三个问题,严重性依次增加。
1.脏读
一个事务读取到另一个事物还没提交的数据,叫做脏读。(当时学到这里会很疑惑,为什么明明没有提交,却能被读取到数据,难道在事务操作时写入了磁盘吗)
2.不可重复读
一个事物先后读取同一条记录,两次结果不一样,叫做不可重复读。不可重复读一般是由针对某条记录的更新操作造成的。
3.幻读
一个事务在查询时没有记录,但是插入时又发现了一条记录,前后查询结构不一致,叫做幻读。幻读一般在查询时有其他线程增删造成。
不可重复读和幻读可以区别记忆。
4.隔离级别:
数据库采用了不同的策略应对并发问题,这种策略叫隔离级别
1.READ UNCOMMITTED:中文意思可以读未提交的,这就解开了我之前的疑问,事务提交前的改动能不能被读取到看的是配置功能。
这个是数据库最低的隔离级别,允许脏读、不可重复读、幻读
2.READ COMMITTED:可以读提交的数据。
该级别禁止了脏读,但是允许不可重复读、幻读
3.REPEATABLE READ:MySQL默认隔离级别
该级别禁止了脏读和不可重复读,但是允许幻读
4.SERIALIZABLE:串行化,性能较低
该级别禁止了脏读、不可重复读、幻读
5.DEFAULT:Spring提供了一个额外选项,它使用数据库默认的隔离级别
5.事务失效
要想理解事务的失效原因,必须知道事务的实现是AOP,而AOP的实现是CGlib,CGlib特有的继承式代理造成一系列原因。
- 方法的自调用:这算是个比较正式的考点,在开启了事务的方法中调用本类下的其他方法(即使这个方法也开启了事务)就会导致失效。因为开了事务的方法是AOP生成的代理类调用的,当他调用被代理类其他方法时,调用的是未被事务增强过的方法(方法本身)这个问题即使控制传播行为也无法解决。
解决方法:
(1)自己注入自己
(2)方法拆分到新的类中
(3)@EnableAspectJAutoProxy(exposeProxy = true) + AopContext.currentProxy() - 方法是private:由于CGlib创建的代理类是继承自目标类,目标类中的private方法子类访问不到
- 方法是final:和private同理,CGlib的继承结构决定了这些关键字的限制
以上三个方法都是由于AOP机制引起的
- 单独的线程调用方法(异步调用):异步调用开启了新线程,而新线程中没有之前的数据库连接信息
- 抛出了特定异常:默认回滚的异常为RuntimeExpection和Error,如果需要自定义可以在@Transactional中指定rollbackfor
- 方法中捕获了异常:如果你在方法中主动捕获异常而没有抛出,事务管理器无法回滚
- 错误的传播行为:如果你指定了NOT_SUPPORTED或NEVER这种不支持事务的传播行为,就会失效
- 类没有被Spring管理或数据源和连接池没有被Spring管理
6.依赖注入的方式
- 构造器注入:注入的Bean不可变。当出现多个重载的构造函数,可以用@Autowire指定要注入的函数。会出现循环依赖。
- setter注入
- 属性注入
Spring推荐使用构造器注入而不是属性注入,因为构造器注入可以保证属性不为null值,同时属性不可变(相当于用了final修饰)
7.AOP的通知类型
- Before:前置通知,在方法执行前被调用
- After-Returning:后置通知,在方法完成时被调用
- After-Throwing:异常通知,在方法抛出异常时被调用
- After:最终通知,在方法执行完成后被调用,无论方法是否成功
- Round:环绕通知,在方法执行前后调用
8.循环依赖和三级缓存
想要读懂循环依赖需要先理清Bean的生命周期
循环依赖:Spring中两个Bean相互依赖,比如A中需要注入B,B中要注入A
解决方法:三级缓存
三级缓存:
一级缓存里存放了完整的Bean,也叫单例池
二级缓存里存放了刚完成实例化的Bean。从Bean的生命周期我们可以知道,此时的Bean还没有到属性赋值(依赖注入)这一环,所以不会有循环依赖
三级缓存里存放了Bean对应的工厂类,用来专门处理代理对象的循环依赖问题
回到我们举得ABA循环依赖的例子,
1.当你创建A时,先在实例化之后将这个不完整的A放到二级缓存,下一步要注入B时,会去一级缓存里找,没有再去二级缓存里找,都没有就创建B。
2.同样的,B在实例化完成之后要注入A,在二级缓存里找到了这个不完整的A,将他注入,完成后续的生命周期直到完成创建,此时会将B放入一级缓存。
3.这时我们回到还没完成的第1条,A找到了在一级缓存的B,可以顺利执行注入,完成相关生命周期。
其实只需要二级缓存就能解决循环依赖问题,但因为代理类的存在,需要额外设置三级缓存。
如果不设置三级缓存,那二级缓存里存放的都是原始的Bean,AOP的功能就用不了
如果把代理类提前创建放到二级缓存里,那就违反了Bean的生命周期,因为代理类的创建是在Bean的初始化的BeanPostProcessor执行的,而二级缓存是在实例化之后就开始了。
9.Spring的模块
- Spring Core:Spring的核心模块,实现了IOC和DI的功能
- Spring AOP:提供了面向切面编程的能力,Spring集成了AspectJ的部分功能来帮助开发者实现非侵入式的代码增强
- Spring Beans:创建和管理了Bean的生命周期
- Spring Context:上下文功能,提供国际化、时间监听、资源访问、环境信息获取等功能
- Spring MVC:提供了Web开发的MVC三层架构
- Spring Data:提供了一整套完整的持久化解决方案
10.SpringAOP和AspectJ的区别
SpringAOP:运行时的代理机制(动态代理);基于Spring框架,适用于Spring容器管理的Bean;轻量级,使用方便
AspectJ:支持编译时、类加载时、运行时AOP;更加灵活的切入和增强;编译器和加载期的织入方式,性能较高
11.Spring MVC的理解
MVC是一种编程思想,规定了Web开发中的Model、View、Controller三层。
SpringMVC是对传统MVC的一种拓展,将Model拆分成了业务模型(Service)和数据模型(Repository),将Controller拆分成了DispatchServlet和Controller。简单来说,SpringMVC就是Spring结合Servlet实现的MVC架构。
DispatchServlet接收请求,并交给HandlerMapping,根据请求路径匹配合适的后端控制器Controller,这中间会经过HanderAdapter将数据绑定到对象并交给Controller。控制器返回ModelAndView对象会交给ViewResolver解析出前端页面返回
拦截器会在HanderAdapter调用preHandler,在控制器返回时调用postHandler
12.Spring的优点
- IOC,控制反转和依赖注入简化了开发过程,降低了耦合度
- AOP,非侵入式地增强了代码
- 生态丰富,Spring集成了所有主流的java开发技术栈
- 社区活跃,文档丰富,解决方案多
13.Spring的设计模式
- 单例模式:毫无疑问,Spring最核心的功能就是实现了单例Bean
- 工厂模式:同上,整个Spring容器就是一个大型的Bean工厂
- 观察者模式:Spring设有监听器来监听各个事件的发布
- 适配器模式:SpringMVC中有一个HandlerAdapter专门处理相关适配
- 代理模式:AOP就是通过代理对象完成的方法增强
- 模板方法模式:Spring提供了很多的Template给开发者调用
14.Spring的父子容器
指的是在Spring整合SpringMVC时通常会出现2个容器,他们之间呈现父子关系
父容器通常是Spring的Bean容器,子容器通常是一个Web容器如Servlet容器
子容器可以访问父容器中的Bean,可以方便访问Service和Dao
父容器无法访问子容器的Bean,避免了不必要的耦合
避免了重复Bean的冲突
15.Spring的启动流程
- 读取配置
- 实例化容器
- 解析BeanDefinitions
- 执行Bean生命周期
- 发布事件
- 完成启动