Spring基础
1.Spring容器机制
容器是Spring实现功能的基础,所有配置过的类被纳入容器,通过容器对象管理bean。
1.1 BeanFactory接口
最基本的容器接口,定义创建和管理bean的方法

1.2 ApplicationContext接口
建立在BeanFactory接口之上

1.3 容器启动过程
- BeanDifinition的Resource定位: 容器需要找到具体的Resource(XML或注解),定位由ResouceLoader统一的Resource接口完成
- BeanDifinition载入: 将
配置信息转化为容器内部的数据结构(BeanDifinition) - BeanDifinition注册:将其注册到容器,通过HashMap持有BeanDifinition数据,这个过程调用BeanDifinitionRegisty接口实现。
1.4 BeanFactory和ApplicationContext
- BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。
- ApplicationContext是BeanFactory的子接口,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
继承MessageSource,因此支持国际化。
统一的资源文件访问方式。
提供在监听器中注册bean的事件。
同时加载多个配置文件。
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
1.4.1 加载方式
- BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。
- ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
1.4.2 创建方式
- BeanFactory通常以编程的方式被创建
- ApplicationContext还能以声明的方式创建,如使用ContextLoader。
1.4.3 注册方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,
但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
1.4.4 关系

- BeanFactory:理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。
- ApplicationContext:高级容器,定义了一个 refresh 方法,用于刷新整个容器,即重新加载/刷新所有的 bean。依赖而不是继承低级容器
2.AOP
1.介绍
Aspect Oriented Programming 面向切面编程,将程序中的相同业务逻辑进行横向隔离,将重复的业务逻辑抽取到一个独立的模块。
-
Aspect(切面):横切关注点的模块化,包含切点和通知
-
Join point(连接点):程序执行过程中能够插入切面的点
-
Pointcut(切点):定义在哪些连接点上应用通知
-
Advice(通知):切面在特定连接点上执行的代码
Before advice:在方法执行前执行
After returning advice:在方法成功执行后执行
After throwing advice:在方法抛出异常后执行
After advice:在方法执行后执行(无论是否成功)
Around advice:环绕方法执行,可以控制方法的执行 -
Target object(目标对象):被一个或多个切面所通知的对象
-
Proxy(代理):AOP框架创建的对象,用于实现切面合约
-
Weaving(织入):将切面与其他对象连接以创建被通知对象的过程
2.实现机制
2.1 JDK动态代理
JDK代理只能为接口创建代理实例
使用 Java 原生的 java.lang.reflect.Proxy 类
- LoginService接口
public interface LoginService {
public void login();
}
- LoginServiceImpl
public class LoginServiceImpl implements LoginService{
@Override
public void login() {
System.out.println("Login");
}
}
- PerformHandler类
public class PerformHandler implements InvocationHandler {
private Object target;
public PerformHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强的方法
System.out.println("start");
//执行被代理类的原方法
Object invoke = method.invoke(target, args);
System.out.println("end");
return invoke;
}
}
- Test类
@Test
public void fun(){
LoginService loginService = new LoginServiceImpl();
//通过Proxy生成代理对象
PerformHandler performHandler = new PerformHandler(loginService);
loginService = (LoginService) Proxy.newProxyInstance(loginService.getClass().getClassLoader(),
loginService.getClass().getInterfaces(),performHandler);
loginService.login();
}
2.2 CGLib动态代理
CGLib动态代理为类创建实例 底层字节码技术 继承的方式实现
依靠Enhancer类创建代理实例 MethodInterceptor接口织入方法
- CglibProxy
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
//生成代理对象
public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
//回调方法 拦截目标类所有方法调用
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("start");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("end");
return invoke;
}
}
- Test类
@Test
public void funG(){
CglibProxy cglibProxy = new CglibProxy();
//创建代理对象
LoginServiceImpl loginService = (LoginServiceImpl) cglibProxy.getProxy(LoginServiceImpl.class);
loginService.login();
}
3.实现方法
3.1 XML
- spring.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean name="loginService" class="service.LoginServiceImpl"></bean>
<bean name = "xmlAdvice" class="service.XmlAdvice"></bean>
<!-- Spring Aop-->
<aop:config>
<!-- 切点-->
<aop:pointcut id="pointcut" expression="execution(* service.LoginServiceImpl.*(..))"/>
<!-- 切面-->
<aop:aspect ref="xmlAdvice">
<!-- 前置-->
<aop:before method="before" pointcut-ref="pointcut"></aop:before>
<!-- 返回-->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"></aop:after-returning>
<!-- 环绕-->
<aop:around method="around" pointcut-ref="pointcut"></aop:around>
<!-- 异常-->
<aop:after-throwing method="afterException" pointcut-ref="pointcut"></aop:after-throwing>
<!-- 后置-->
<aop:after method="after" pointcut-ref="pointcut"></aop:after>
</aop:aspect>
</aop:config>
</beans>
- Test类
@Test
public void funXml(){
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring1.xml");
LoginService loginService = context.getBean("loginService", LoginService.class);
loginService.login();
}
3.2 注解
- Spring.xml 修改
<bean name="annoAdvice" class="service.AnnoAdvice"></bean>
<!-- 自动动态代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean name="loginService" class="service.LoginServiceImpl"></bean>
- AnnoAdvice类
@Aspect
public class AnnoAdvice {
//切点
@Pointcut("execution(* service.LoginServiceImpl.*(..))")
public void pointcut(){
}
@Before("pointcut()")
public void before(){
System.out.println("before");
}
//后置通知 异常不执行
@AfterReturning("pointcut()")
public void afterReturning(){
System.out.println("afterReturning");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable{
System.out.println("around start");
Object object = point.proceed();
System.out.println("around end");
return object;
}
@AfterThrowing("pointcut()")
public void afterException(){
System.out.println("Exception");
}
@After("pointcut()")
public void after(){
System.out.println("after");
}
}
4.应用
4.1 性能监控
- Service1
public class Service1 {
public void service() throws Exception{
System.out.println("service");
Thread.sleep(1000);
}
}
- Record类:记录执行信息
public class Record {
private String className;
private String methodName;
private Date recordTime;
private Long expendTime;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Date getRecordTime() {
return recordTime;
}
public void setRecordTime(Date recordTime) {
this.recordTime = recordTime;
}
public Long getExpendTime() {
return expendTime;
}
public void setExpendTime(Long expendTime) {
this.expendTime = expendTime;
}
@Override
public String toString() {
return "Record{" +
"className='" + className + '\'' +
", methodName='" + methodName + '\'' +
", recordTime=" + recordTime +
", expendTime=" + expendTime +
'}';
}
}
- RecordAspect类
@Aspect
public class RecordAspect {
@Pointcut("execution(* applicationAop.Service* .*(..))")
public void record(){
}
@Around("record()")
public Object recordTime(ProceedingJoinPoint point) throws Throwable{
String className = point.getTarget().getClass().getName();
String methodName = point.getSignature().getName();
//方法执行时间
long startTime = System.currentTimeMillis();
Object result = point.proceed();
long time = System.currentTimeMillis() - startTime;
Record record = new Record();
record.setExpendTime(time);
record.setClassName(className);
record.setMethodName(methodName);
record.setRecordTime(new Date());
System.out.println(record);
return result;
}
}
- xml配置
<bean name="service1" class="applicationAop.Service1"></bean>
<bean name="recordAspect" class="applicationAop.RecordAspect"></bean>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- Test类
@Test
public void test() throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring1.xml");
Service1 service1 = context.getBean("service1",Service1.class);
service1.service();
}
4.2 异常监控
- MyException类
public class MyException extends Exception{
private static final long serialVersionUID = 1l;
private String msg;
public MyException(String msg) {
super();
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
- Service2
public class Service2 {
public void service() throws Exception{
System.out.println("service2");
if(true){
throw new MyException("true");
} else {
System.out.println(false);
}
}
}
- Message类
public class Message {
private String className;
private String methodName;
private Date recordTime;
private String exceptionMsg;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Date getRecordTime() {
return recordTime;
}
public void setRecordTime(Date recordTime) {
this.recordTime = recordTime;
}
public String getExceptionMsg() {
return exceptionMsg;
}
public void setExceptionMsg(String exceptionMsg) {
this.exceptionMsg = exceptionMsg;
}
@Override
public String toString() {
return "Message{" +
"className='" + className + '\'' +
", methodName='" + methodName + '\'' +
", recordTime=" + recordTime +
", exceptionMsg='" + exceptionMsg + '\'' +
'}';
}
}
- MessageAspect
@Aspect
public class MessageAspect {
@Pointcut("execution(* applicationAop.Service* .*(..))")
public void exceptionMsg(){
}
@Around("exceptionMsg()")
public Object msgMethod(ProceedingJoinPoint point) throws Throwable{
String className = point.getTarget().getClass().getName();
String methodName = point.getSignature().getName();
try {
return point.proceed();
}catch (MyException e){
Message message = new Message();
message.setClassName(className);
message.setMethodName(methodName);
message.setRecordTime(new Date());
message.setExceptionMsg(e.getMsg());
System.out.println(message);
}
return null;
}
}
- xml配置
<bean name="service2" class="applicationAop.Service2"></bean>
<bean name="mmessageAspect" class="applicationAop.MessageAspect"></bean>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-Test类
@Test
public void test1() throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring1.xml");
Service2 service2 = context.getBean("service2",Service2.class);
service2.service();
}
3.IOC
IOC:控制反转,对象控制权由代码交给容器,负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
DI:依赖注入,为控制反转提供实现方法。
1.DI方式
- 构造器注入
- 属性注入
- 接口注入(废弃)
1.1 构造器注入
在被注入的类声明一个构造方法(有参或无参),Spring通过反射调用构造方法,进而创建对象
1.2 属性注入
在被注入类声明set方法,通过参数注入
- Student
public class Student {
public Student(String msg) {
this.msg = msg;
}
public Student(){
}
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "Student{" +
"msg='" + msg + '\'' +
'}';
}
}
- spring.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd"
xmlns:p="http://www.springframework.org/schema/p">
<bean id="student" class="entity.Student">
<!-- 1.构造器注入属性值
通过构造器-->
<constructor-arg name="msg" value="MSG"></constructor-arg>
<!-- 2.属性注入
通过set方法-->
<property name="msg">
<value>LWX</value>
</property>
<!-- 3.接口注入-->
</bean>
</beans>
- Test类
@Test
public void fun(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("config/spring.xml");
Student student = applicationContext.getBean("student",Student.class);
System.out.println(student.getMsg());
}
2.DI方式
2.1 注入集合
- Mix实体
public class Mix {
private List<String> list;
private Map<String, String> map;
private String[] arr;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public String[] getArr() {
return arr;
}
public void setArr(String[] arr) {
this.arr = arr;
}
@Override
public String toString() {
return "Mix{" +
"list=" + list +
", map=" + map +
", arr=" + Arrays.toString(arr) +
'}';
}
}
- spring.xml
<bean id="mix" class="entity.Mix">
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<property name="map">
<map>
<entry key="key1" value="map1"></entry>
<entry key="key2" value="map2"></entry>
</map>
</property>
<property name="arr">
<array>
<value>arr1</value>
<value>arr2</value>
</array>
</property>
</bean>
2.2 注入对象属性
利用ref元素
- Clazz实体
public class Clazz {
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Clazz{" +
"students=" + students +
'}';
}
}
- spring.xml
<bean id="clazz" class="entity.Clazz">
<!-- 第一种-->
<property name="students">
<list>
<ref bean="student"></ref>
</list>
</property>
<!-- 第二种-->
<property name="students" ref="student"></property>
</bean>
2.3 P命名空间注入
上述实体
- spring.xml
beans加入xmlns:p="http://www.springframework.org/schema/p
<!-- p命名空间-->
<bean id="clazz" class="entity.Clazz" p:students-ref="student"></bean>
2.3 SpEL注入
Spring Expression Language 表达式语言 为Bean属性进行动态赋值 通过bean的id引用bean 调用对象方法或属性
- Person实体
public class Person {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "Person{" +
"msg='" + msg + '\'' +
'}';
}
}
- spring.xml
<!-- SpEL注入-->
<bean id="person" class="entity.Person">
<property name="msg" value="#{student.msg}"></property>
</bean>
4.Bean
4.1 配置

4.2 作用域
容器创建bean实例时可以指定其作用域,默认singleton

4.3 生命周期
- 实例化 Instantiation : createBeanInstance()
- InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation和postProcessAfterInstantiation
- 属性赋值 Populate : populateBean()
- 初始化 Initialization : initializeBean()
- 如果实现了xxxAware 接口,通过不同类型的Aware接口拿到Spring容器的资源
- 如果实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation 和postProcessAfterInitialization 方法
- 如果配置了init-method 方法,则会执行init-method 配置的方法
- 销毁 Destruction
- 容器关闭后,如果Bean实现了DisposableBean 接口,则会回调该接口的destroy 方法
- 如果配置了destroy-method 方法,则会执行destroy-method 配置的方法
bean创建,初始化,销毁的过程。
- 初始化之前:init-method属性或实现initializingBean接口
- 销毁之前:destroy-method属性或实现DisposableBean接口
- Bean01实体
public class Bean01 implements DisposableBean {
public Bean01(){
}
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void init(){
System.out.println("INIT");
}
public void close(){
System.out.println("CLOSE");
}
@Override
public void destroy() throws Exception {
}
}
- spring.xml
<bean id="bean01" class="entity.Bean01" init-method="init" destroy-method="close">
<property name="value" value="MyValue"></property>
</bean>
4.4 注解
- spring.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<context:component-scan base-package="entity"></context:component-scan>
</beans>
- stu实体类
@Component("stu")
public class Stu {
public Stu(String msg) {
this.msg = msg;
}
public Stu(){
}
@Value("MSG")
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "Student{" +
"msg='" + msg + '\'' +
'}';
}
}
- Sch实体类
@Component("sch")
@Scope(scopeName = "singleton")
public class Sch {
@Autowired
@Qualifier("stu")//注入该实例
private Stu stu;
@PostConstruct
public void init(){
System.out.println("INIT");
}
@PreDestroy
public void close(){
System.out.println("CLOSE");
}
}
5.事务
5.1 分类
- 编程式事务:在代码中显式地开启、提交或回滚事务
- 声明式事务:通过配置来实现的,不需要在代码中显式地管理事务。是通过 AOP 实现的。Spring 提供了两种声明式事务的方式:基于 XML配置和基于注解配置
5.2 架构

5.2.1 俩种模式
- 策略模式
PlatformTransactionManager 基类,实现了 事务执行设计到的三个核心方法,去实现它
TransactionAspectSupport 中, 会有一个determineTransactionManager 方法, 动态的从IOC容器,加载 注册了的PlatformTransactionManager 实现类 - 动态代理模式
动态代理有JDK的动态代理、 Aspectj的动态代理,SpringAOP动态代理
![image]()
SpringAOP实现的大致思路:
1.配置获取Advisor (顾问):拦截器+AOP匹配过滤器,生成Advisor
2.生成代理:根据Advisor生成代理对象,会生成JdkDynamicAopProxy或CglibAopProxy
3.执行代理:代理类执行代理时,从Advisor取出拦截器,生成MethodInvocation(连接点)并执行代理
过程。
5.3 事务传播机制
Propagation 属性
- REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
a1 b1 b2 回滚
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
A(a1); //调用A入参a1
testB(); //调用testB
}
@Transactional(propagation = Propagation.REQUIRED)
public void testB(){
B(b1); //调用B入参b1
throw Exception; //发生异常抛出
B(b2); //调用B入参b2
}
- REQUIRES_NEW:每次执行都会创建新事务,并同时将上下文中的事务挂起,执行完当前线程后再恢复上下文中事务。
a1 回滚 b1 b2 成功 (B是新事物 和A独立)
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
A(a1); //调用A入参a1
testB(); //调用testB
throw Exception; //发生异常抛出
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testB(){
B(b1); //调用B入参b1
B(b2); //调用B入参b2
}
- SUPPORTS:如果上下文中存在事务则加入当前事务,如果没有事务则以非事务方式执行。
a1 b1 成功 b2 失败 (A无事务,B按非事务执行,如果A有事务,B也有事务)
public void testMain(){
A(a1); //调用A入参a1
testB(); //调用testB
}
@Transactional(propagation = Propagation.SUPPORTS)
public void testB(){
B(b1); //调用B入参b1
throw Exception; //发生异常抛出
B(b2); //调用B入参b2
}
- NOT_SUPPORTED:当上下文中有事务则挂起当前事务,执行完当前逻辑后再恢复上下文事务。
a1 b2 失败 b1 成功 (B按无事务执行 b1成功 b2失败 A有事务 a1失败)
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
A(a1); //调用A入参a1
testB(); //调用testB
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testB(){
B(b1); //调用B入参b1
throw Exception; //发生异常抛出
B(b2); //调用B入参b2
}
- MANDATORY:该传播级别要求上下文中必须存在事务,否则抛出异常。
a1成功 b1 b2失败 (B无事务,抛异常)
public void testMain(){
A(a1); //调用A入参a1
testB(); //调用testB
}
@Transactional(propagation = Propagation.MANDATORY)
public void testB(){
B(b1); //调用B入参b1
throw Exception; //发生异常抛出
B(b2); //调用B入参b2
}
- NEVER:该传播级别要求上下文中不能存在事务,否则抛出异常。
B直接抛出事务异常 A回滚 都失败
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
A(a1); //调用A入参a1
testB(); //调用testB
}
@Transactional(propagation = Propagation.NEVER)
public void testB(){
B(b1); //调用B入参b1
B(b2); //调用B入参b2
}
- NESTED:嵌套事务,如果上下文中存在事务则嵌套执行,如果不存在则新建事务
都回滚
@Transactional(propagation = Propagation.REQUIRED)
public void testMain(){
A(a1); //调用A入参a1
testB(); //调用testB
throw Exception; //发生异常抛出
}
@Transactional(propagation = Propagation.NESTED)
public void testB(){
B(b1); //调用B入参b1
B(b2); //调用B入参b2
}
5.4 事务异常处理
spring事务只对RuntimeException奏效,同一个Service类中的方法相互调用需要使用注入的对象来调用,不要直接使用this.方法名来调用,this.方法名调用是对象内部方法调用,不会通过Spring代理,也就是事务不会起作用,通过aop来获取异常,如果手动捕获则不会回滚
- 正常回滚
@PostMapping("/test")
@Transactional
public void test() {
transPlatformAccessMapper.insertTest();
int i = 1/0;
}
- 不会回滚
@PostMapping("/test")
@Transactional
public void test() {
try{
transPlatformAccessMapper.insertTest();
int i = 1/0;
}catch (Exception e){
e.printStackTrace();
}
}
5.4.1 手动回滚
- 回滚点
@PostMapping("/test")
@Transactional
public void test() {
//设置回滚点,只回滚以下异常
Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
try{
transPlatformAccessMapper.insertTest();
int i = 1/0;
}catch (Exception e){
e.printStackTrace();
//手工回滚到回滚点
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
}
}
- 全部回滚
@PostMapping("/test")
@Transactional
public void test() {
try{
transPlatformAccessMapper.insertTest();
int i = 1/0;
}catch (Exception e){
e.printStackTrace();
// 全部回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
5.5 @Tranasctional
- 当它被用于类上时,它表示该类中所有的方法都将被包含在同一个事务中。当它被用于方法上时,它表示该方法将被包含在一个新的事务中。
- 只能用在public 方法上,如果用在protected或者private的方法上,不会报错,但是该注解不会生效。
- 默认情况下,@Transactional注解只能回滚 非检查型异常,具体为RuntimeException及其子类和Error子类
- 如果需要对检查型异常(Checked Exception)进行回滚,可以使用rollbackFor 属性来定义回滚的异常类型,使用 propagation 属性定义事务的传播行为。
@Transactional(rollbackFor = Exception.class,propagation =Propagation.REQUIRED)
- 不能回滚被try{}catch() 捕获的异常。
- 只能对在被Spring 容器扫描到的类下的方法生效。
6.循环依赖
首先,Spring 解决循环依赖有两个前提条件:
- 不全是构造器方式的循环依赖
- 必须是单例
本质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化的对象。
第三级缓存:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象
第二级缓存:用来保存实例化完成,但是未初始化完成的对象
第一级缓存:用来保存实例化、初始化都完成的对象

5.1 AB相互依赖
A对象的创建过程:
1.创建对象A,实例化的时候把A对象工厂放入三级缓存
2.A注入属性时,发现依赖B,转而去实例化B

3.同样创建对象B,注入属性时发现依赖A,依次从一级到三级缓存查询A,从三级缓存通过对象工厂拿到A,把A放入二级缓存,同时删除三级缓存中的A,
然后,B已经实例化并且初始化完成,把B放入一级缓存。

4.接着继续创建A,顺利从一级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除二级缓存中的A,同时把A放入一级缓存
5.最后,一级缓存中保存着实例化、初始化都完成的A、B对象

因此,由于把实例化和初始化的流程分开了,所以如果都是用构造器的话,就没法分离这个操作,所以都是构造器的话就无法解决循环依赖的问题了。
5.2 二级缓存
不可以,主要是为了生成代理对象。
因为三级缓存中放的是生成具体对象的匿名内部类,他可以生成代理对象,也可以是普通的实例对象。
使用三级缓存主要是为了保证不管什么时候使用的都是一个对象。
假设只有二级缓存的情况,往二级缓存中放的显示一个普通的Bean对象,在BeanPostProcessor 去生
成代理对象之后,覆盖掉二级缓存中的普通Bean对象,那么多线程环境下可能取到的对象就不一致
了。

6.注解
6.1 @Autowired @Resource
@Autowired可用于:构造函数、成员变量、Setter方法
@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。


浙公网安备 33010602011771号