spring5基础
# bean的生命周期
①Spring IOC容器可以管理bean的生命周期,Spring允许在bean生命周期内特定的时间点执行指定的任务。
②Spring IOC容器对bean的生命周期进行管理的过程:
[1]通过构造器或工厂方法创建bean实例
[2]为bean的属性设置值和对其他bean的引用
[3]调用bean的初始化方法
[4]bean可以使用了
[5]当容器关闭时,调用bean的销毁方法
③在配置bean时,通过init-method
和destroy-method
属性为bean指定初始化和销毁方法
# ④bean的后置处理器
[1]bean后置处理器允许在调用初始化方法前后对bean进行额外的处理
[2]bean后置处理器对IOC容器里的所有bean实例逐一处理,而非单一实例。其典型应用是:检查bean属性的正确性或根据特定的标准更改bean的属性。
[3] bean后置处理器时需要实现接口:
org.springframework.beans.factory.config.BeanPostProcessor
。在初始化方法被调用前后,Spring将把每个bean实例分别传递给上述接口的以下两个方法:- postProcessBeforeInitialization(Object, String)
- postProcessAfterInitialization(Object, String)
⑤添加bean后置处理器后bean的生命周期
[1]通过构造器或工厂方法创建bean实例
[2]为bean的属性设置值和对其他bean的引用
[3]将bean实例传递给bean后置处理器的**postProcessBeforeInitialization()**方法
[4]调用bean的初始化方法
[5]将bean实例传递给bean后置处理器的**postProcessAfterInitialization()**方法
[6]bean可以使用了
[7]当容器关闭时调用bean的销毁方法
在指定要扫描的包时,
<context:component-scan>
元素会自动注册一个bean的后置处理器:AutowiredAnnotationBeanPostProcessor
的实例。该后置处理器可以自动装配标记了@Autowired、@Resource或@Inject注解的属性。
public class Car {
public Car(){
System.out.println("car contructor ...");
}
public void init(){
System.out.println("Car初始化");
}
public void destory(){
System.out.println("Car销毁");
}
}
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@Import({Color.class, Animal.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MyConfig2 {
@Bean(initMethod = "init",destroyMethod = "destory")
public Car car(){
return new Car();
}
}
2
3
4
5
6
7
8
# Bean的初始化与销毁
# 方式一:@Bean指定init-method和destory-method
- 在实体类中创建初始化和销毁方法
- 在配置文件中,注入bean时指定初始化和销毁方法
# 方式二:通过实现InitializingBean和DisposableBean接口
- 通过让bean实现InitialzingBean接口来定义初始化逻辑,实现DisposableBean接口来定义销毁逻辑。
- 在配置类中注入Build的bean
# 方式三:使用JSR250规范
@PostConstruct:在bean创建完成并且属性值赋值完成后执行初始化;
@PreDestroy:在容器销毁bean之前,通知容器进行清理工作;
- 创建一个Dog类,并在初始化和销毁方法上添加对应的注解
- 在配置类中注入Dog对应的bean
参考文档: Spring注解驱动---IOC · 语雀 (yuque.com) (opens new window)
# el表达式
很多框架如springsecurity的权限表达式里面支持el表达式
SpEL使用
#{…}
作为定界符,所有在大框号中的字符都将被认为是SpEL表达式
# 泛型依赖注入
# 完全注解开发
1、创建配置类,替代 xml 配置文件
@Configuration //作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
}
2
3
4
2、加载配置类
(2)编写测试类
@Test
public void testService2() {
//加载配置类
ApplicationContext context= new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService",
UserService.class);
System.out.println(userService);
userService.add();
}
2
3
4
5
6
7
8
9
10
# JdbcTemplate
相关包: spring-jdbc-XX.RELEASE.jar、spring-orm-XX.RELEASE.jar、spring-tx-XX.RELEASE.jar
Spring的JdbcTemplate看作是一个小型的轻量级持久化层框架,和我们之前使用过的DBUtils风格非常接近
# 数据源对象
数据源有很多,如com.mchange.v2.c3p0.ComboPooledDataSource
# JdbcTemplate对象
# Spring事务管理
# 1、编程式事务
即将事务的开启、关闭与业务代码写在一起,使用原生的JDBC API实现事务管理是所有事务管理方式的基石,同时也是最典型的编程式事务管理
[1]获取数据库连接Connection对象
[2]取消事务的自动提交
[3]执行操作
[4]正常完成操作时手动提交事务
[5]执行失败时回滚事务
[6]关闭相关资源
# 2、声明式事务
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
事务管理代码的固定模式作为一种横切关注点,可以通过AOP方法模块化,进而借助Spring AOP
框架实现声明式事务管理。
Spring在不同的事务管理API之上定义了一个抽象层,通过配置的方式使其生效,从而让应用程序开发人员不必了解事务管理API的底层实现细节,就可以使用Spring的事务管理机制。
# 事务管理器
Spring的核心事务管理抽象是PlatformTransactionManager
。它为事务管理封装了一组独立于技术的方法。无论使用Spring的哪种事务管理策略(编程式或声明式),事务管理器都是必须的
# spring事务的7种传播机制
# 1、PROPAGATION_REQUIRED
若当前存在事务,则加入该事务,若不存在事务,则新建一个事务。
class C1(){
@Transactional(propagation = Propagation.REQUIRED)
function A(){
C2.B();
}
}
class C2(){
@Transactional(propagation = Propagation.REQUIRED)
function B(){
do something;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
若B方法抛出异常,A方法进行捕获,A会抛出异常,因为C2标志回滚,C1标志提交,产生冲突。
若B方法抛出异常,B方法内部捕获,A、B都不会回滚。
若A或B抛出异常,但没有捕获,则A、B都回滚。
A、B可操作同一条记录,因为处于同一个事务中。
# 2、PAOPAGATION_REQUIRE_NEW
若当前没有事务,则新建一个事务。若当前存在事务,则新建一个事务,新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交。
若B方法抛出异常,A方法进行捕获,B方法回滚,A方法不受B异常影响。
若B方法抛出异常,B方法内部捕获,A、B都不会回滚。
若A方法抛出异常,不会影响B正常执行。
若B方法抛出异常,A、B方法都没有处理,则A、B都会回滚。
A、B不可操作同一条记录,因为处于不同事务中,会产生死锁。
# 3、PROPAGATION_NESTED
如果当前存在事务,则嵌套在当前事务中执行。如果当前没有事务,则新建一个事务,类似于REQUIRE_NEW。 若B方法抛出异常,A方法进行捕获,B方法回滚,A方法正常执行。
若A或者B抛出异常,不做任何处理的话,A、B都要回滚。
A、B可操作同一条记录,因为处于同一个事务中。
# 4、PROPAGATION_SUPPORTS
支持当前事务,若当前不存在事务,以非事务的方式执行。
# 5、PROPAGATION_NOT_SUPPORTED
以非事务的方式执行,若当前存在事务,则把当前事务挂起。 A、B不可操作同一条记录,因为A是事务执行,B在A尚未提交前再操作同一条记录,会产生死锁。
# 6、PROPAGATION_MANDATORY
强制事务执行,若当前不存在事务,则抛出异常
# 7、PROPAGATION_NEVER
以非事务的方式执行,如果当前存在事务,则抛出异常。
# spring事务的四种隔离级别
# 1、事务的四大特性(ACID)
# 原子性
操作要么全部成功,要么全部失败回滚。
# 一致性
事务执行前和执行后处于一致性状态。例如,转账前A、B共5000元,A、B之间转账后,两者之和仍应该是5000元。
# 隔离性
事务之间互不干扰。
# 持久性
事务一旦提交,数据的改变是永久性的,即使这时候数据库发生故障,数据也不会丢失。
# 2、与事务隔离级别的相关问题
# 脏读
A事务对一条记录进行修改,尚未提交,B事务已经看到了A的修改结果。若A发生回滚,B读到的数据就是错误的,这就是脏读。简言之:读到了未提交事务修改后的值
# 不可重复读
A事务对一条记录进行修改,尚未提交,B事务第一次查询该记录,看到的是修改之后的结果,此时A发生回滚,B事务又一次查询该记录,看到的是回滚后的结果。同一个事务内,B两次查询结果不一致,这就是不可重复读。
# 幻读
A事务对所有记录进行修改,尚未提交,此时B事务创建了一条新记录,A、B都提交。A查看所有数据,发现有一条数据没有被修改,因为这是B事务新增的,就想看到了幻象一样,这就是幻读。
# 3、事务的隔离级别
# 读未提交(read uncommitted) oracle不支持
事务尚未提交,其他事务即可以看到该事务的修改结果。隔离级别最差,脏读、不可重复读、幻读都不能避免。
# 读已提交(read committed) oracle默认隔离级别
事务只能看到其他事务提交之后的数据。可避免脏读,不可重复读、幻读无法避免。
不可重复读原因:A事务修改,B事务查询,A提交前和提交后,B事务看到的数据是不一致的。
幻读原因:A事务修改,B事务新增,B事务提交前,A事务已经提交。B事务提交后,A发现仍有数据未修改。
# 可重复读(repeatable read)-------mysql innodb默认隔离级别 oracle不支持
一个事务多次查询,无论其他事务对数据如何修改,看到的数据都是一致的。因为A事务查询数据时,若B同时在修改数据,A事务看到的永远是B事务执行前的数据。只有当A提交或者回滚之后,看到的才是最新的被B修改知乎的数据。可避免脏读、不可重复读,幻读无法避免。
# 序列化(serializable)
事务顺序执行,可避免脏读、不可重复读、幻读,但效率最差。因为A事务执行时,其他事务必须等待。
# Spring 如何解决循环依赖
Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的
- Spring是通过递归的方式获取目标bean及其所依赖的bean的;
- Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean(半成品),然后为其注入属性。