切换默认shell到wsl

This commit is contained in:
2023-01-10 21:59:13 +08:00
parent 1d6198e9d8
commit be40280c8c
33 changed files with 5387 additions and 5387 deletions

View File

@@ -1,15 +1,15 @@
# POJO
## POJO定义
POJOPlain Old Java Object是一种直接的类型POJO并不包含对任何框架的引用。
> 对于POJO类型该类属性和方法的定义并没有特定的约束和限制
## Java Bean命名约束
由于对POJO本身并没有对POJO类属性和方法的定义强制指定命名约束因而许多框默认支持Java Bean命名约束。
> ### Java Bean命名约束
> 在Java Bean命名约束中为POJO类属性和方法的命名指定了如下规则
> 1. 属性的访问权限都被设置为private属性通过getter和setter向外暴露
> 2. 对于方法的命名getter和setter遵循getXXX/setXXX的命名规范对于boolean属性的getter可以使用isXXX形式
> 3. Java Bean命名规范要求Java Bean对象需要提供无参构造方法
> 4. 实现Serializable接口能够将对象以二进制的格式进行存储
## 其他命名规范
由于Java Bean命名规范中有些规则强制对Java Bean的命名进行限制可能会带来弊端故而如今许多框架在接受Java Bean命名规范之余仍然支持其他的POJO命名规范
> 如在Spring中通过@Component注解注册Bean对象时被@Component注解的类并不一定要实现Serializable接口也不一定要拥有无参构造方法。
# POJO
## POJO定义
POJOPlain Old Java Object是一种直接的类型POJO并不包含对任何框架的引用。
> 对于POJO类型该类属性和方法的定义并没有特定的约束和限制
## Java Bean命名约束
由于对POJO本身并没有对POJO类属性和方法的定义强制指定命名约束因而许多框默认支持Java Bean命名约束。
> ### Java Bean命名约束
> 在Java Bean命名约束中为POJO类属性和方法的命名指定了如下规则
> 1. 属性的访问权限都被设置为private属性通过getter和setter向外暴露
> 2. 对于方法的命名getter和setter遵循getXXX/setXXX的命名规范对于boolean属性的getter可以使用isXXX形式
> 3. Java Bean命名规范要求Java Bean对象需要提供无参构造方法
> 4. 实现Serializable接口能够将对象以二进制的格式进行存储
## 其他命名规范
由于Java Bean命名规范中有些规则强制对Java Bean的命名进行限制可能会带来弊端故而如今许多框架在接受Java Bean命名规范之余仍然支持其他的POJO命名规范
> 如在Spring中通过@Component注解注册Bean对象时被@Component注解的类并不一定要实现Serializable接口也不一定要拥有无参构造方法。

View File

@@ -1,109 +1,109 @@
# SpEL(Spring Expression Language)
- ## SpEL的用法
- SpEL如何将表达式从字符串转化为计算后的值
- 在转化过程中在parseExpression方法执行时可能会抛出ParseException异常在执行getValue方法时可能会抛出EvaluationException
```java
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();
```
- 在SpEL中获取String的字节数组
```java
ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("'Hello World'.bytes");
byte[] bytes=(byte[])exp.getValue();
```
- 在调用Expression类型的getValue方法时可以不用进行强制类型转换而是在getValue方法中传入一个Class参数返回值将会被自动转换成Class对应的目标类型当转换失败时会抛出EvaluationException
```java
ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("'Hello World'.bytes.length");
Integer bytes=exp.getValue(Integer.class);
```
- SpEL可以针对特定的对象给出一个表达式并且在getValue方法中传入一个对象那么表达式中的变量将会针对该对象中的特定属性
```java
// 如下步骤会比较waifu对象的name属性是否为"touma"字符串
ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("name=='touma'");
Boolean equals=exp.getValue(waifu,Boolean.class);
```
- 可以为parser设置一个parserconfiguration用于处理当列表或集合元素的index操作超过集合长度时的默认行为
```java
class Demo {
public List<String> list;
}
// Turn on:
// - auto null reference initialization
// - auto collection growing
SpelParserConfiguration config = new SpelParserConfiguration(true, true);
ExpressionParser parser = new SpelExpressionParser(config);
Expression expression = parser.parseExpression("list[3]");
Demo demo = new Demo();
Object o = expression.getValue(demo);
// demo.list will now be a real collection of 4 entries
// Each entry is a new empty String
```
- ## SpEL在bean对象定义时的使用
- 在使用@Value注解时可以结合SpEL表达式进行使用@Value注解可以运用在域变量、方法、方法和构造器的参数上。@Value会指定默认值
- ## SpEL对List、Map的支持
- 可以通过{}来直接表示list
```java
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);
```
- 可以通过{key:value}形式来直接表示map空map用{:}来进行表示
```java
// evaluates to a Java map containing the two entries
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);
```
- 可以通过new int[]{}的形式为SpEL指定数组
```java
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
// Array with initializer
int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);
// Multi dimensional array
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
```
- ## SpEL支持的特殊操作符
- instanceof
```java
boolean falseValue = parser.parseExpression(
"'xyz' instanceof T(Integer)").getValue(Boolean.class);
```
- 正则表达式
```java
boolean trueValue = parser.parseExpression(
"'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
```
- 类型操作符获取类型的Class对象、调用静态方法
```java
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
boolean trueValue = parser.parseExpression(
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
.getValue(Boolean.class);
```
- new操作符
- 可以在SpEL表达式中通过new操作符来调用构造器但是除了位于java.lang包中的类对其他的类调用构造器时都必须指定类的全类名
```java
Inventor einstein = p.parseExpression(
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
.getValue(Inventor.class);
// create new Inventor instance within the add() method of List
p.parseExpression(
"Members.add(new org.spring.samples.spel.inventor.Inventor(
'Albert Einstein', 'German'))").getValue(societyContext);
# SpEL(Spring Expression Language)
- ## SpEL的用法
- SpEL如何将表达式从字符串转化为计算后的值
- 在转化过程中在parseExpression方法执行时可能会抛出ParseException异常在执行getValue方法时可能会抛出EvaluationException
```java
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();
```
- 在SpEL中获取String的字节数组
```java
ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("'Hello World'.bytes");
byte[] bytes=(byte[])exp.getValue();
```
- 在调用Expression类型的getValue方法时可以不用进行强制类型转换而是在getValue方法中传入一个Class参数返回值将会被自动转换成Class对应的目标类型当转换失败时会抛出EvaluationException
```java
ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("'Hello World'.bytes.length");
Integer bytes=exp.getValue(Integer.class);
```
- SpEL可以针对特定的对象给出一个表达式并且在getValue方法中传入一个对象那么表达式中的变量将会针对该对象中的特定属性
```java
// 如下步骤会比较waifu对象的name属性是否为"touma"字符串
ExpressionParser parser=new SpelExpressionParser();
Expression exp=parser.parseExpression("name=='touma'");
Boolean equals=exp.getValue(waifu,Boolean.class);
```
- 可以为parser设置一个parserconfiguration用于处理当列表或集合元素的index操作超过集合长度时的默认行为
```java
class Demo {
public List<String> list;
}
// Turn on:
// - auto null reference initialization
// - auto collection growing
SpelParserConfiguration config = new SpelParserConfiguration(true, true);
ExpressionParser parser = new SpelExpressionParser(config);
Expression expression = parser.parseExpression("list[3]");
Demo demo = new Demo();
Object o = expression.getValue(demo);
// demo.list will now be a real collection of 4 entries
// Each entry is a new empty String
```
- ## SpEL在bean对象定义时的使用
- 在使用@Value注解时可以结合SpEL表达式进行使用@Value注解可以运用在域变量、方法、方法和构造器的参数上。@Value会指定默认值
- ## SpEL对List、Map的支持
- 可以通过{}来直接表示list
```java
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);
```
- 可以通过{key:value}形式来直接表示map空map用{:}来进行表示
```java
// evaluates to a Java map containing the two entries
Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue(context);
Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue(context);
```
- 可以通过new int[]{}的形式为SpEL指定数组
```java
int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context);
// Array with initializer
int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context);
// Multi dimensional array
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
```
- ## SpEL支持的特殊操作符
- instanceof
```java
boolean falseValue = parser.parseExpression(
"'xyz' instanceof T(Integer)").getValue(Boolean.class);
```
- 正则表达式
```java
boolean trueValue = parser.parseExpression(
"'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
```
- 类型操作符获取类型的Class对象、调用静态方法
```java
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
boolean trueValue = parser.parseExpression(
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
.getValue(Boolean.class);
```
- new操作符
- 可以在SpEL表达式中通过new操作符来调用构造器但是除了位于java.lang包中的类对其他的类调用构造器时都必须指定类的全类名
```java
Inventor einstein = p.parseExpression(
"new org.spring.samples.spel.inventor.Inventor('Albert Einstein', 'German')")
.getValue(Inventor.class);
// create new Inventor instance within the add() method of List
p.parseExpression(
"Members.add(new org.spring.samples.spel.inventor.Inventor(
'Albert Einstein', 'German'))").getValue(societyContext);
```

View File

@@ -1,177 +1,177 @@
# Spring AOP
- ## Spring AOP的核心概念
- Aspect切面一个模块化的考虑
- Joint Point连接点程序执行时的一个时间点通常是方法的执行
- Advice当切面在一个切入点执行多做时执行的动作被称之为AdviceAdvice有不同的类型before、after、around
- Pointcut切入点advice通常运行在满足pointcut的join point上pointcut表达式与join point相关联Spring中默认使用AspectJ切入点表达式
- Introduction在类中声明新的方法、域变量甚至是接口实现
- linking将应用类型或对象和切面链接起来
- ## Spring AOP的类型
- before在连接点之前运行但是无法阻止后续连接点的执行
- after returning在连接点正常返回之后进行
- after throwing在链接点抛出异常正常退出之后进行
- after finally上两种的结合不管连接点是正常退出还是抛出异常退出都会在其之后执行
- aroundaround可以自定义连接点之前和之后的执行内容其也能够选择时候执行连接点的方法
- ## Spring AOP的特点
- 区别于AspectJ AOP框架Spring AOP框架是基于代理来实现的
- 对于实现了接口的类Spring AOP通常是通过JDK动态代理来实现的对于没有实现接口的类Spring AOP是通过cglib来实现的
- 可以强制Spring AOP使用cglib在如下场景
- 如果想要advise类中方法而该方法没有在接口中定义
- 如果想要将代理对象传递给一个具有特定类型的方法作为参数
- ## Spring AOP的AspectJ注解支持
- Spring AOP支持AspectJ注解Spring AOP可以解释和AspectJ 5相同的注解通过使用AspectJ提供的包来进行切入点解析和匹配
- 但是即使使用了AspectJ注解AOP在运行时仍然是纯粹的Spring AOP项目不需要引入AspectJ的编译器和weaver
- Spring AOP对AspectJ注解支持的开启
- 通过@EnableAspectJAutoProxy注解会自动的为满足切入点匹配的连接点bean对象创建移动代理对象
```java
@Configuration
@EnableAspectJAutoProxy
class AspectJConfiguration {
// ...
}
```
- ## 声明Spring AOP切面
- 在容器中任何bean对象如其类型具有@AspectJ注解将会被自动探知到并且用来配置spring aop
- 在Spring AOP中aspect其自身是无法作为其他aspect的目标对象的。被标记为@Aspect的类不仅标明其为aspect并且将其从自动代理中排除
- 如果为某个bean对象配置了切面那么在后续创建该bean对象时实际上是创建该bean对象的代理对象
```java
@Component // 将该类型声明为bean对象
@Aspect // 声明切面
public class ProxyAspect {
}
```
- ## 声明Spring AOP切入点
- 由于Spring AOP仅仅支持方法的连接点故而可以将切入点看做对bean对象方法的匹配
- Join Point expression的种类
- execution匹配目标方法的执行可以在括号中接收一个函数签名包含返回类型、函数名和函数参数类型
```java
// 被@JointPoint注解标注的方法必须具有void的返回类型
@Pointcut("execution(* Point.*(..))")
void methodInjected() {
}
```
- within:匹配声明在某一特定类中的方法
```java
@Pointcut("within(Point)")
```
- this匹配生成的代理对象为该类型的一个实例
- target匹配目标对象为该类型的一个实例
- args匹配特定参数
- @args传递参数的类型具有指定的注解
- @target运行时该对象的类具有指定的注解
- @within运行时执行的方法其方法定义在具有指定注解的类中可以是继承父类的方法父类指定了注解
- @annotation执行的方法具有指定注解
- Spring AOP同样支持将JoinPoint匹配为具有特定name的Spring bean对象
```java
@Pointcut("bean(nameA) || bean(nameB))")
```
- ## Spring AOP中的Advice
- Advice和Pointcut Expresion相关联主要可以分为before、after、around等种类
- Before
```java
@Before("execution(* Point.*(..))")
public void doSomething() {
}
```
- AfterReturning:
```java
// AfterReturning支持获取切入点执行后返回的值
@AfterReturning(
pointcut="execution(* Point.*(..))",
returning="retVal")
public void doSomething(int retVal) {
}
```
- AfterThrowing:
```java
@AfterThrowing(
pointcut="execution(* Point.*())",
throwing="ex"
)
public void doSomething(Throwable ex) {
}
```
- After:After不管是切入点正常返回还是抛出异常都会执行类似于finally
```java
@After("execution(* Point.*())")
public void doSomething() {
}
```
- Around:其方法必须会一个Oject类型的返回值并且方法的第一个参数类型是ProceedingJoinPoint
```java
@Around("execution(* Point.*())")
public Object doSomething(ProceedingJoinPoint pjp) {
return isCacheExisted()?returnFromCache():pjp.proceed();
}
```
- ## Spring AOP中Advice方法对JoinPoint的访问
- 任何advice方法都可以声明声明其第一个参数为JoinPoint类型。@Around标注的adivce方法其第一个参数的类型必须为ProceedingJoinPoint类型该类型为JoinPoint的子类型
- JoinPoint接口具有如下方法
- getArgs返回方法参数
- getThis返回代理对象
- getTarget返回目标对象
- getSignature返回函数的签名
- toString返回该advice方法的描述信息
- ## Advice方法通过参数来获取传递给底层方法的参数
- 在pointcut表达式的args中如果用advice方法中的参数名来代替参数类型那么该类型的参数值会被传递给该参数
```java
@Before("execution(* Point.*(..) && args(position,..))")
public void adviceMethod(Position position) {
}
```
- 或者可以通过如下方式先通过一个Pointcut获取参数在在另一个方法中获取named pointcut已获取的参数
```java
// 此时adviceMethodTwo同样能够获取Position参数
@Pointcut("execution(* Point.*(..)) && args(position,..)")
public void adviceMethodOne(Position position) {
}
@Before("adviceMethodOne(position)")
public void adviceMethodTwo(Position position) {
}
```
- Spring AOP可以通过如下方式来约束泛型的参数
```java
@Before("execution(* GenericsInterface+.method(*) && args(param))")
public void adviceMethod(DesiredType param) {
}
```
- ## 通过Spring AOP对参数进行预处理
```java
@Around("execution(* Point.area(*) && args(width,height))")
public double caculateInCM(ProceedingJoinPoint jp,double width,double height) {
width*=100;
height*=100;
return jp.proceed(width,height);
}
```
- ## Spring AOP中多个advice对应到同一个Pointcut
- 如果多个advice都具有相同的pointcut那么多个advice之间的执行顺序是未定义的。可以为Aspect类实现Ordered接口或者添加@Order标记来定义该advice的执行优先级那么具有具有较小order值的方法将会优先被执行
- ## Spring AOP Introduction
- 在Spring AOP中可以通过Introduction来声明一个对象继承了某接口并且为被代理的对象提供被继承接口的实现
- 可以通过@DeclareParent注解为指定对象添加接口并且指明该接口默认的实现类完成后可以直接将生成的代理对象复制给接口变量
```java
@Aspect
public class MyAspect {
@DeclareParent(value="cc.rikakonatsumi.interfaces.*+",defaultImpl=DefaultImpl.class)
private static MyInterface myInterface;
// 之后可以直接通过this(ref)在pointcut表达式中获取服务对象也可以通过getBean方法获取容器中的对象
}
```
- ## @RestControllerAdvice的使用
- @RestControllerAdvice是@Componnent注解的一个特例@RestControllerAdivce注解的组成包含@Component
- @RestControllerAdivce组合了@ControllerAdvice和@ResponseBody两个注解
- 通常,@RestControllerAdvice用作为spring mvc的所有方法做ExceptionHandler
# Spring AOP
- ## Spring AOP的核心概念
- Aspect切面一个模块化的考虑
- Joint Point连接点程序执行时的一个时间点通常是方法的执行
- Advice当切面在一个切入点执行多做时执行的动作被称之为AdviceAdvice有不同的类型before、after、around
- Pointcut切入点advice通常运行在满足pointcut的join point上pointcut表达式与join point相关联Spring中默认使用AspectJ切入点表达式
- Introduction在类中声明新的方法、域变量甚至是接口实现
- linking将应用类型或对象和切面链接起来
- ## Spring AOP的类型
- before在连接点之前运行但是无法阻止后续连接点的执行
- after returning在连接点正常返回之后进行
- after throwing在链接点抛出异常正常退出之后进行
- after finally上两种的结合不管连接点是正常退出还是抛出异常退出都会在其之后执行
- aroundaround可以自定义连接点之前和之后的执行内容其也能够选择时候执行连接点的方法
- ## Spring AOP的特点
- 区别于AspectJ AOP框架Spring AOP框架是基于代理来实现的
- 对于实现了接口的类Spring AOP通常是通过JDK动态代理来实现的对于没有实现接口的类Spring AOP是通过cglib来实现的
- 可以强制Spring AOP使用cglib在如下场景
- 如果想要advise类中方法而该方法没有在接口中定义
- 如果想要将代理对象传递给一个具有特定类型的方法作为参数
- ## Spring AOP的AspectJ注解支持
- Spring AOP支持AspectJ注解Spring AOP可以解释和AspectJ 5相同的注解通过使用AspectJ提供的包来进行切入点解析和匹配
- 但是即使使用了AspectJ注解AOP在运行时仍然是纯粹的Spring AOP项目不需要引入AspectJ的编译器和weaver
- Spring AOP对AspectJ注解支持的开启
- 通过@EnableAspectJAutoProxy注解会自动的为满足切入点匹配的连接点bean对象创建移动代理对象
```java
@Configuration
@EnableAspectJAutoProxy
class AspectJConfiguration {
// ...
}
```
- ## 声明Spring AOP切面
- 在容器中任何bean对象如其类型具有@AspectJ注解将会被自动探知到并且用来配置spring aop
- 在Spring AOP中aspect其自身是无法作为其他aspect的目标对象的。被标记为@Aspect的类不仅标明其为aspect并且将其从自动代理中排除
- 如果为某个bean对象配置了切面那么在后续创建该bean对象时实际上是创建该bean对象的代理对象
```java
@Component // 将该类型声明为bean对象
@Aspect // 声明切面
public class ProxyAspect {
}
```
- ## 声明Spring AOP切入点
- 由于Spring AOP仅仅支持方法的连接点故而可以将切入点看做对bean对象方法的匹配
- Join Point expression的种类
- execution匹配目标方法的执行可以在括号中接收一个函数签名包含返回类型、函数名和函数参数类型
```java
// 被@JointPoint注解标注的方法必须具有void的返回类型
@Pointcut("execution(* Point.*(..))")
void methodInjected() {
}
```
- within:匹配声明在某一特定类中的方法
```java
@Pointcut("within(Point)")
```
- this匹配生成的代理对象为该类型的一个实例
- target匹配目标对象为该类型的一个实例
- args匹配特定参数
- @args传递参数的类型具有指定的注解
- @target运行时该对象的类具有指定的注解
- @within运行时执行的方法其方法定义在具有指定注解的类中可以是继承父类的方法父类指定了注解
- @annotation执行的方法具有指定注解
- Spring AOP同样支持将JoinPoint匹配为具有特定name的Spring bean对象
```java
@Pointcut("bean(nameA) || bean(nameB))")
```
- ## Spring AOP中的Advice
- Advice和Pointcut Expresion相关联主要可以分为before、after、around等种类
- Before
```java
@Before("execution(* Point.*(..))")
public void doSomething() {
}
```
- AfterReturning:
```java
// AfterReturning支持获取切入点执行后返回的值
@AfterReturning(
pointcut="execution(* Point.*(..))",
returning="retVal")
public void doSomething(int retVal) {
}
```
- AfterThrowing:
```java
@AfterThrowing(
pointcut="execution(* Point.*())",
throwing="ex"
)
public void doSomething(Throwable ex) {
}
```
- After:After不管是切入点正常返回还是抛出异常都会执行类似于finally
```java
@After("execution(* Point.*())")
public void doSomething() {
}
```
- Around:其方法必须会一个Oject类型的返回值并且方法的第一个参数类型是ProceedingJoinPoint
```java
@Around("execution(* Point.*())")
public Object doSomething(ProceedingJoinPoint pjp) {
return isCacheExisted()?returnFromCache():pjp.proceed();
}
```
- ## Spring AOP中Advice方法对JoinPoint的访问
- 任何advice方法都可以声明声明其第一个参数为JoinPoint类型。@Around标注的adivce方法其第一个参数的类型必须为ProceedingJoinPoint类型该类型为JoinPoint的子类型
- JoinPoint接口具有如下方法
- getArgs返回方法参数
- getThis返回代理对象
- getTarget返回目标对象
- getSignature返回函数的签名
- toString返回该advice方法的描述信息
- ## Advice方法通过参数来获取传递给底层方法的参数
- 在pointcut表达式的args中如果用advice方法中的参数名来代替参数类型那么该类型的参数值会被传递给该参数
```java
@Before("execution(* Point.*(..) && args(position,..))")
public void adviceMethod(Position position) {
}
```
- 或者可以通过如下方式先通过一个Pointcut获取参数在在另一个方法中获取named pointcut已获取的参数
```java
// 此时adviceMethodTwo同样能够获取Position参数
@Pointcut("execution(* Point.*(..)) && args(position,..)")
public void adviceMethodOne(Position position) {
}
@Before("adviceMethodOne(position)")
public void adviceMethodTwo(Position position) {
}
```
- Spring AOP可以通过如下方式来约束泛型的参数
```java
@Before("execution(* GenericsInterface+.method(*) && args(param))")
public void adviceMethod(DesiredType param) {
}
```
- ## 通过Spring AOP对参数进行预处理
```java
@Around("execution(* Point.area(*) && args(width,height))")
public double caculateInCM(ProceedingJoinPoint jp,double width,double height) {
width*=100;
height*=100;
return jp.proceed(width,height);
}
```
- ## Spring AOP中多个advice对应到同一个Pointcut
- 如果多个advice都具有相同的pointcut那么多个advice之间的执行顺序是未定义的。可以为Aspect类实现Ordered接口或者添加@Order标记来定义该advice的执行优先级那么具有具有较小order值的方法将会优先被执行
- ## Spring AOP Introduction
- 在Spring AOP中可以通过Introduction来声明一个对象继承了某接口并且为被代理的对象提供被继承接口的实现
- 可以通过@DeclareParent注解为指定对象添加接口并且指明该接口默认的实现类完成后可以直接将生成的代理对象复制给接口变量
```java
@Aspect
public class MyAspect {
@DeclareParent(value="cc.rikakonatsumi.interfaces.*+",defaultImpl=DefaultImpl.class)
private static MyInterface myInterface;
// 之后可以直接通过this(ref)在pointcut表达式中获取服务对象也可以通过getBean方法获取容器中的对象
}
```
- ## @RestControllerAdvice的使用
- @RestControllerAdvice是@Componnent注解的一个特例@RestControllerAdivce注解的组成包含@Component
- @RestControllerAdivce组合了@ControllerAdvice和@ResponseBody两个注解
- 通常,@RestControllerAdvice用作为spring mvc的所有方法做ExceptionHandler

View File

@@ -1,183 +1,183 @@
# Spring Core IOC
- ## IOC容器和bean简介
- IOC简介
- IOC控制反转也被称之为依赖注入DI对象通过构造函数参数、工厂方法参数、或者在构造后通过setter来设置属性来定义依赖。在对象被创建时IOC容器会将依赖注入到bean对象中
- IOC容器
- IOC容器接口
- BeanFactoryBeanFactory是一个接口提供了高级配置功能来管理任何类型的对象
- ApplicationContextApplicationContext是BeanFactory的一个子接口在BeanFactory的基础上其添加了一些更为特殊的特性。
- IOC容器职责
- IOC容器负责来初始化、配置、组装bean对象
- ## 基于注解的Spring容器配置
- @Required
- @Required应用于bean对象属性的setter方法表示该属性在配置时必须被填充通过依赖注入或是用xml定义bean时显式指定值
- 该注解当前已经被弃用
- @Autowired
- 通过在构造函数上标明@Autowired来对方法参数进行注入
- 当在构造函数上标记@Autowired时,如果当前类中只有一个构造函数,那么@Autowired注解可以被省略;如果当前类有多个构造函数,那么应该在某个构造函数上指明@Autowired注解
```java
@Component
class Shiromiya {
private JdbcTemplate jdbcTemplate;
@Autowired
public Shiromiya(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate=jdbcTemplate;
}
}
```
- 同样可以在setter上应用@Component
```java
@Component
class Shiromiya {
private JdbcTemplate jdbcTemplate;
@Autowired
public setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate=jdbcTemplate;
}
}
```
- 将@Autowired应用于字段
```java
@Component
class Shiromiya {
@Autowired
private JdbcTemplate jdbcTemplate;
}
```
- 通过@Autowired获取相同类型的所有bean对象
```java
@Component
class Shiromiya {
private String[] waifus;
/*
* 这里同样也支持Collections类型
* 例如 List<String>
*/
@Autowired
public Shiromiya(String[] waifus) {
this.waifus=waifus;
}
}
// 同样可以通过Map类型来获取所有相同类型bean对象的name和value
// key对应bean对象的name
// value对应该bean对象的值
@Component
class Shiromiya {
private Map<String,String> waifus;
@Autowired
public void setWaifus(Map<String,String> waifus) {
this.waifus=waifus;
}
}
```
- 在@Autowired标记在构造函数上时即使required为true在参数为多bean类型时即使没有匹配的bean该属性会赋值为{}(空集合)而不是抛出异常
- @Autowired作用与构造函数的规则
- 当required属性为其默认值true时在bean类型中只有一个构造函数可以用@Autowired标注
- 如果bean类型中有多个构造函数标注了@Autowired注解那么那么他们都必须将required属性设置为false并且所有标注了@Autowired属性的构造函数都会被视为依赖注入的候选构造函数
- 如果有多个候选的构造函数那么在IOC容器中可以满足的匹配bean最多的构造函数将会被选中
- 如果没有候选函数被选中,那么其会采用默认构造函数,如无默认构造函数,则抛出异常
- 如果bean有多个构造函数并且所有构造函数都没有标明@Autowired注解那么会采用默认构造函数如果默认构造函数不存在抛出异常
- 如果bean类型只有一个构造函数那么该构造函数会被用来进行依赖注入即使该构造函数没有标注@Autowired注解
- 除了使用@Autowired的required属性还可以使用@Nullable注解来标注可为空
```java
@Component
public class Shiromiya {
@Autowired
@Nullable
private int num;
}
```
- @Primary
- @Autowired注解是通过类型注入如果相同类型存在多个bean时可以通过@Primary注解来表明一个primary bean
```java
@Configuration
public class BeanConfiguration {
@Bean
@Primary
public String name_1() {
return "kazusa";
}
@Bean
public String name_2() {
return "ogiso";
}
}
/*
* 此时,若通过@Autowired注入String类型“kazusa”将会是默认值
*/
```
- @Qualifier
- 可以通过@Qualifier来指定bean的name导入特定bean并且可以为bean指定默认的qualifier
```java
@Component
public class Shiromiya {
@Autowired
@Qualifier("name_2")
private String n_2;
private String n_1;
@Autowired
public Shiromiya(@Qualifier("name_1") String n) {
this.n_1=n;
}
}
```
- bean对象的qualifier并不需要唯一可以为不同的bean对象赋值相同的qualifier并且在注入bean集合的时候根据qualifier过滤
```java
@Configuration
@Qualifier("config")
class BeanConfiguration {
@Bean
@Qualifier("name")
public String name_1() {
return "kazusa";
}
@Bean
@Qualifier("name")
public String name_2() {
return "ogiso";
}
@Bean
@Qualifier("not-name")
public String not_name_1() {
return "fuck";
}
}
@Component
public class Person {
/* 此nameList属性会注入qualifier为name的所有bean
* 在此处为"kazusa"和"ogiso"
*/
@Autowired
@Qualifier("name")
Map<String,String> nameList;
@Autowired
@Qualifier("config")
BeanConfiguration conf;
@Override
public String toString() {
return "Person{" +
"nameList=" + nameList +
", conf=" + conf +
'}';
}
}
```
- 作为一种回退机制当bean的qualifier未被定义时bean的name属性将会被作为其qualifierautowired时会根据@Qualifier注解中指定的值匹配具有相同name的bean对象
- 若想根据bean的name进行匹配无需@Qualifier注解只需要将注入点的name(filed的变量名标注为@Autowired函数的形参名)和bean的name进行比较如果相同则匹配成功否则匹配失败
- @Autowired同样支持自身引用的注入但是自身引用的注入只能作为一种fallback机制。如果当前IOC容器中存在其他的同类型对象那么其他对象会被优先注入对象自己并不会参与候选的对象注入。但是如果IOC中并不存在其他同类型对象那么自身对象将会被作为引用注入。
- @Resource
- @Resource标签类似于@Autowired标签,但是@Resource具有一个name属性用来匹配bean对象的name属性
# Spring Core IOC
- ## IOC容器和bean简介
- IOC简介
- IOC控制反转也被称之为依赖注入DI对象通过构造函数参数、工厂方法参数、或者在构造后通过setter来设置属性来定义依赖。在对象被创建时IOC容器会将依赖注入到bean对象中
- IOC容器
- IOC容器接口
- BeanFactoryBeanFactory是一个接口提供了高级配置功能来管理任何类型的对象
- ApplicationContextApplicationContext是BeanFactory的一个子接口在BeanFactory的基础上其添加了一些更为特殊的特性。
- IOC容器职责
- IOC容器负责来初始化、配置、组装bean对象
- ## 基于注解的Spring容器配置
- @Required
- @Required应用于bean对象属性的setter方法表示该属性在配置时必须被填充通过依赖注入或是用xml定义bean时显式指定值
- 该注解当前已经被弃用
- @Autowired
- 通过在构造函数上标明@Autowired来对方法参数进行注入
- 当在构造函数上标记@Autowired时,如果当前类中只有一个构造函数,那么@Autowired注解可以被省略;如果当前类有多个构造函数,那么应该在某个构造函数上指明@Autowired注解
```java
@Component
class Shiromiya {
private JdbcTemplate jdbcTemplate;
@Autowired
public Shiromiya(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate=jdbcTemplate;
}
}
```
- 同样可以在setter上应用@Component
```java
@Component
class Shiromiya {
private JdbcTemplate jdbcTemplate;
@Autowired
public setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate=jdbcTemplate;
}
}
```
- 将@Autowired应用于字段
```java
@Component
class Shiromiya {
@Autowired
private JdbcTemplate jdbcTemplate;
}
```
- 通过@Autowired获取相同类型的所有bean对象
```java
@Component
class Shiromiya {
private String[] waifus;
/*
* 这里同样也支持Collections类型
* 例如 List<String>
*/
@Autowired
public Shiromiya(String[] waifus) {
this.waifus=waifus;
}
}
// 同样可以通过Map类型来获取所有相同类型bean对象的name和value
// key对应bean对象的name
// value对应该bean对象的值
@Component
class Shiromiya {
private Map<String,String> waifus;
@Autowired
public void setWaifus(Map<String,String> waifus) {
this.waifus=waifus;
}
}
```
- 在@Autowired标记在构造函数上时即使required为true在参数为多bean类型时即使没有匹配的bean该属性会赋值为{}(空集合)而不是抛出异常
- @Autowired作用与构造函数的规则
- 当required属性为其默认值true时在bean类型中只有一个构造函数可以用@Autowired标注
- 如果bean类型中有多个构造函数标注了@Autowired注解那么那么他们都必须将required属性设置为false并且所有标注了@Autowired属性的构造函数都会被视为依赖注入的候选构造函数
- 如果有多个候选的构造函数那么在IOC容器中可以满足的匹配bean最多的构造函数将会被选中
- 如果没有候选函数被选中,那么其会采用默认构造函数,如无默认构造函数,则抛出异常
- 如果bean有多个构造函数并且所有构造函数都没有标明@Autowired注解那么会采用默认构造函数如果默认构造函数不存在抛出异常
- 如果bean类型只有一个构造函数那么该构造函数会被用来进行依赖注入即使该构造函数没有标注@Autowired注解
- 除了使用@Autowired的required属性还可以使用@Nullable注解来标注可为空
```java
@Component
public class Shiromiya {
@Autowired
@Nullable
private int num;
}
```
- @Primary
- @Autowired注解是通过类型注入如果相同类型存在多个bean时可以通过@Primary注解来表明一个primary bean
```java
@Configuration
public class BeanConfiguration {
@Bean
@Primary
public String name_1() {
return "kazusa";
}
@Bean
public String name_2() {
return "ogiso";
}
}
/*
* 此时,若通过@Autowired注入String类型“kazusa”将会是默认值
*/
```
- @Qualifier
- 可以通过@Qualifier来指定bean的name导入特定bean并且可以为bean指定默认的qualifier
```java
@Component
public class Shiromiya {
@Autowired
@Qualifier("name_2")
private String n_2;
private String n_1;
@Autowired
public Shiromiya(@Qualifier("name_1") String n) {
this.n_1=n;
}
}
```
- bean对象的qualifier并不需要唯一可以为不同的bean对象赋值相同的qualifier并且在注入bean集合的时候根据qualifier过滤
```java
@Configuration
@Qualifier("config")
class BeanConfiguration {
@Bean
@Qualifier("name")
public String name_1() {
return "kazusa";
}
@Bean
@Qualifier("name")
public String name_2() {
return "ogiso";
}
@Bean
@Qualifier("not-name")
public String not_name_1() {
return "fuck";
}
}
@Component
public class Person {
/* 此nameList属性会注入qualifier为name的所有bean
* 在此处为"kazusa"和"ogiso"
*/
@Autowired
@Qualifier("name")
Map<String,String> nameList;
@Autowired
@Qualifier("config")
BeanConfiguration conf;
@Override
public String toString() {
return "Person{" +
"nameList=" + nameList +
", conf=" + conf +
'}';
}
}
```
- 作为一种回退机制当bean的qualifier未被定义时bean的name属性将会被作为其qualifierautowired时会根据@Qualifier注解中指定的值匹配具有相同name的bean对象
- 若想根据bean的name进行匹配无需@Qualifier注解只需要将注入点的name(filed的变量名标注为@Autowired函数的形参名)和bean的name进行比较如果相同则匹配成功否则匹配失败
- @Autowired同样支持自身引用的注入但是自身引用的注入只能作为一种fallback机制。如果当前IOC容器中存在其他的同类型对象那么其他对象会被优先注入对象自己并不会参与候选的对象注入。但是如果IOC中并不存在其他同类型对象那么自身对象将会被作为引用注入。
- @Resource
- @Resource标签类似于@Autowired标签,但是@Resource具有一个name属性用来匹配bean对象的name属性
- @Resource标签首先会对具有相同name的bean对象如果没有匹配到具有相同name的bean对象才会fallback到类型匹配

View File

@@ -1,71 +1,71 @@
# Spring Data Access
- ## Spring事务
- 本地事务和全局事务:
- 全局事务:全局事务允许使用多个事务资源,应用服务器来对全局事务进行管理
- 本地事务:本地事务无法管理多个事务资源
- 本地事务和全局事务的优缺点
- 全局事务的使用需要和服务器环境相绑定,降低了代码的重用性
- 本地事务无法使用多个事务资源无法通过JTA等框架来对多个事务资源进行管理无法使用分布式事务
- ## 声明式事务
- Spring中声明式事务是通过AOP来实现的
- 在声明式事务中,可以为方法级的粒度指定事务行为
- 声明式事务的回滚规则:
- 在Spring声明式事务中可以为事务指定回滚规则即指定针对哪些异常事务会自动执行回滚操作
- 在默认情况下只有抛出unchecked异常通常为RuntimeException声明式事务才会进行回滚
- 声明式事务的实现细节:
- 声明式事务通过aop代理实现并且事务的advice是通过xml元数据配置来驱动的
- aop和事务元数据联合产生了一个aop代理对象并且该代理对象通过使用TransactionInterceptor和TransactionManager来实现事务
- @Transactional通常和线程绑定的事务一起工作线程绑定的事务由PlatformTransactionManager管理。@Transactional会将事务暴露给当前执行线程中所有的dao操作
- 声明式事务的回滚:
- 在Spring事务中推荐让事务回滚的方式是在事务执行的方法中抛出一个异常
- Spring事务在默认情况下只会针对unchecked异常RuntimeException进行回滚对于ErrorSpring事务也会执行回滚操作
- checked异常并不会导致事务的回滚操作可以注册rollback rule来指定对特定的异常包括checked异常进行回滚操作
- rollback rule
- 回滚规则rollback rule通常用来指定当一个异常被抛出时是否为该异常执行事务的回滚操作
-@Transactional注解中可以指定rollbackFor/noRollbackFor、rollbackForClassName/noRollbackForClassName来指定为那些异常类执行回滚操作
> 当指定rollbackFor属性为checked异常时如rollbackFor=FileNotFoundException.class)此时指定的异常不会覆盖其默认行为为RuntimeException和Error异常执行回滚操作
> 故而指定后其默认会为Error、RuntimeException、FileNotFoundException三类异常执行回滚操作
```java
@Transactional(rollbackFor={MyException.class})
public void myOperation() {
// ...
}
```
- ## 基于注解的声明式事务
- @Transactional既可以作用于类上,也可以作用于方法上。当作用于类上时,该声明类中所有的方法都会被声明是事务的,该类子类中所有的方法也都是事务的
- @Transactional是可以继承的,被@Inherited元注解修饰
>@Inherited类是元注解,用来修饰注解类。如果一个注解类被@Inherited注解标识那么在对class查询该注解类时如果当前class没有声明该注解将会在当前class的父类中查找该注解依次递归。直到在父类中找到该注解或是到达继承结构的顶部Object类@Inherited标注的注解仅能在类继承中有效,如注解被标注在接口上,那么将@Inherited标注的注解将不会被递归查询到
- 并且class级别的@Transactional并不应用在从父类继承的方法上,即若一个类被@Transactional注解标注,并且该类从父类继承方法,那么该类从父类继承的方法并不会被看作是事务的,除非在该类中重新声明继承的方法。
- 通过在Configuration类上注解@EnableTransactionManagement,配合@Transactional可以将一个bean对象声明是事务的
- 当基于标准spring配置时应该仅将@Transactional注解标注于public方法,当将@Transactional注解标注于非public方法时无效
- 在Spring中仅推荐将@Transactional注解应用于类上不推荐将其应用在接口接口方法上。如果将其应用在接口上那么该事务配置仅仅对基于接口的动态代理有效对基于class的代理无效。
- 当类级别和方法级别都设置了@Transactional注解时,方法级别的设置会优先被使用
- ## @Transactional注解的配置
- 事务的传播: 默认情况下,@Transactional的propagation属性是PROPAGATION_REQUIRED
- 事务的隔离级别: 默认情况下,@Transactional的isolation属性是ISOLATION_DEFAULT,使用数据库默认的隔离级别
- readOnly 默认情况下,@Transactional的readOnly属性是false,默认事务是可读写的
- timeout 默认况下下,@Transactional的超时属性取决于底层的事务系统如果底层事务系统不支持timeout则timeout属性为none
- rollbackFor 默认情况下,@Transactional会针对unchecked异常和Error进行回滚操作
- transactionManager 默认情况下,@Transactional注解会使用项目中默认的事务管理器即bean name为transactionManager的事务管理器。可以为@Transactional注解指定value属性或是transactionManager属性来指定想要采用的事务管理器的bean name或是qualifier
- ## Transaction Propagation
- ### PROPAGATION.REQUIRED
- 在Spring中事务的传播行为默认是PROPAGATION_REQUIRED默认情况下该选项会强制的要求一个物理事务
- 如果当前作用域中不存在事务,那么会创建一个新的事务
- 如果当前作用域的外层作用域已经存在事务,那么会加入到当前作用域的事务中去
- 在Spring中默认情况下当嵌套事务加入到外层的事务中时会忽略内层事务定义的隔离级别、timeout设置和读写标志等。
> 如果想要对外层事务进行验证可以手动将事务管理器的validateExistingTransaction属性设置为true。这样当加入到一个隔离级别与内层事务完全不同的外层事务中时该加入操作会被拒绝。在该设置下如果read-write内层事务想要加入到外层的read-only事务中时该加入操作也会被拒绝。
- 在事务传播行为被设置为PROPAGATION_REQUIRED的情况下会为每个被设置事务的方法创建一个逻辑的事务作用域。各个逻辑事务作用域之间都是相互独立的在不同逻辑事务作用域之间都可以独立设置事务的rollback-only属性。但是在PROPAGATION_REQUIRED的情况下内层事务和外层事务都映射到同一个物理事务内层事务加入到外层事务中故而在内层逻辑事务中为物理事务设置rollback-only会切实影响到外层事务的提交。
- 当事务传播行为被设置为PROPAGATION_REQUIRED时如果内层事务设置了rollback-only标记那么会导致外层物理事务的回滚。当外层事务尝试提交并失败回滚后会抛出一个UnexceptedRollbackException异常外层事务commit方法的调用者会接受到该UnexceptedRollbackException代表内层发生了非预期的回滚操作
- ### PROPAGATION.REQUIRES_NEW
- 相对于PROPAGATION_REQUIREDPROPAGATION.REQUIRES_NEW传播行为会一直使用独立的物理事务而不会尝试区加入外部已经存在的物理事务。
- 对于PROPAGATION_NEW,其内层事务和外层事务都可以独立的提交或回滚,内层事务的回滚并不会导致外层事务的回滚。
- 将事务传播行为设置为PROPAGATION.REQUIRES_NEW时内层事务可以独立定义自己的隔离级别、timeout值、read-only属性而不必继承外部事务的这些属性。在PROPAGATION_REQUIRED中内部事务自定义这些属性将会被忽略内部事务加入外部事务后会采用外部事务的设置。
- ### PROPAGATION.NESTED
- 和PROPAGATION_REQUIRED类似PROPAGATION_NESTED同样也只有一个物理事务。但是其支持多个savepoint存档点该物理事务可以回滚到特定的存档点而非必须回滚整个事务。
- 由于PROPAGATION_NESTED对存档点的支持故而在PROPAGATION_NESTED条件下可以进行部分回滚。内层事务的回滚操作并不会造成外部事务的回滚内层事务回滚后外层事务仍然能够继续执行和提交。
> 由于PROPAGATION_NESTED需要JDBC savepoint存档点的支持故而该设置仅仅对JDBC事务资源有效。
> 当事务被回滚之后,当前事务无法再被提交,故而:
> 若在子事务中已经回滚子事务传播行为为required那么父事务的状态已经被回滚即使父事务捕获子事务抛出的异常那么在捕获异常之后执行的sql操作也不会被提交到数据库中父事务状态处于已回滚无法再次提交
> ***但是当子事务传播行为为nested时子事务虽然和父事务共用一个事务子事务回滚时只会回滚到子事务开启之前的存档点父事务在捕获子事务抛出异常之后执行的sql语句仍然可以被提交***
# Spring Data Access
- ## Spring事务
- 本地事务和全局事务:
- 全局事务:全局事务允许使用多个事务资源,应用服务器来对全局事务进行管理
- 本地事务:本地事务无法管理多个事务资源
- 本地事务和全局事务的优缺点
- 全局事务的使用需要和服务器环境相绑定,降低了代码的重用性
- 本地事务无法使用多个事务资源无法通过JTA等框架来对多个事务资源进行管理无法使用分布式事务
- ## 声明式事务
- Spring中声明式事务是通过AOP来实现的
- 在声明式事务中,可以为方法级的粒度指定事务行为
- 声明式事务的回滚规则:
- 在Spring声明式事务中可以为事务指定回滚规则即指定针对哪些异常事务会自动执行回滚操作
- 在默认情况下只有抛出unchecked异常通常为RuntimeException声明式事务才会进行回滚
- 声明式事务的实现细节:
- 声明式事务通过aop代理实现并且事务的advice是通过xml元数据配置来驱动的
- aop和事务元数据联合产生了一个aop代理对象并且该代理对象通过使用TransactionInterceptor和TransactionManager来实现事务
- @Transactional通常和线程绑定的事务一起工作线程绑定的事务由PlatformTransactionManager管理。@Transactional会将事务暴露给当前执行线程中所有的dao操作
- 声明式事务的回滚:
- 在Spring事务中推荐让事务回滚的方式是在事务执行的方法中抛出一个异常
- Spring事务在默认情况下只会针对unchecked异常RuntimeException进行回滚对于ErrorSpring事务也会执行回滚操作
- checked异常并不会导致事务的回滚操作可以注册rollback rule来指定对特定的异常包括checked异常进行回滚操作
- rollback rule
- 回滚规则rollback rule通常用来指定当一个异常被抛出时是否为该异常执行事务的回滚操作
-@Transactional注解中可以指定rollbackFor/noRollbackFor、rollbackForClassName/noRollbackForClassName来指定为那些异常类执行回滚操作
> 当指定rollbackFor属性为checked异常时如rollbackFor=FileNotFoundException.class)此时指定的异常不会覆盖其默认行为为RuntimeException和Error异常执行回滚操作
> 故而指定后其默认会为Error、RuntimeException、FileNotFoundException三类异常执行回滚操作
```java
@Transactional(rollbackFor={MyException.class})
public void myOperation() {
// ...
}
```
- ## 基于注解的声明式事务
- @Transactional既可以作用于类上,也可以作用于方法上。当作用于类上时,该声明类中所有的方法都会被声明是事务的,该类子类中所有的方法也都是事务的
- @Transactional是可以继承的,被@Inherited元注解修饰
>@Inherited类是元注解,用来修饰注解类。如果一个注解类被@Inherited注解标识那么在对class查询该注解类时如果当前class没有声明该注解将会在当前class的父类中查找该注解依次递归。直到在父类中找到该注解或是到达继承结构的顶部Object类@Inherited标注的注解仅能在类继承中有效,如注解被标注在接口上,那么将@Inherited标注的注解将不会被递归查询到
- 并且class级别的@Transactional并不应用在从父类继承的方法上,即若一个类被@Transactional注解标注,并且该类从父类继承方法,那么该类从父类继承的方法并不会被看作是事务的,除非在该类中重新声明继承的方法。
- 通过在Configuration类上注解@EnableTransactionManagement,配合@Transactional可以将一个bean对象声明是事务的
- 当基于标准spring配置时应该仅将@Transactional注解标注于public方法,当将@Transactional注解标注于非public方法时无效
- 在Spring中仅推荐将@Transactional注解应用于类上不推荐将其应用在接口接口方法上。如果将其应用在接口上那么该事务配置仅仅对基于接口的动态代理有效对基于class的代理无效。
- 当类级别和方法级别都设置了@Transactional注解时,方法级别的设置会优先被使用
- ## @Transactional注解的配置
- 事务的传播: 默认情况下,@Transactional的propagation属性是PROPAGATION_REQUIRED
- 事务的隔离级别: 默认情况下,@Transactional的isolation属性是ISOLATION_DEFAULT,使用数据库默认的隔离级别
- readOnly 默认情况下,@Transactional的readOnly属性是false,默认事务是可读写的
- timeout 默认况下下,@Transactional的超时属性取决于底层的事务系统如果底层事务系统不支持timeout则timeout属性为none
- rollbackFor 默认情况下,@Transactional会针对unchecked异常和Error进行回滚操作
- transactionManager 默认情况下,@Transactional注解会使用项目中默认的事务管理器即bean name为transactionManager的事务管理器。可以为@Transactional注解指定value属性或是transactionManager属性来指定想要采用的事务管理器的bean name或是qualifier
- ## Transaction Propagation
- ### PROPAGATION.REQUIRED
- 在Spring中事务的传播行为默认是PROPAGATION_REQUIRED默认情况下该选项会强制的要求一个物理事务
- 如果当前作用域中不存在事务,那么会创建一个新的事务
- 如果当前作用域的外层作用域已经存在事务,那么会加入到当前作用域的事务中去
- 在Spring中默认情况下当嵌套事务加入到外层的事务中时会忽略内层事务定义的隔离级别、timeout设置和读写标志等。
> 如果想要对外层事务进行验证可以手动将事务管理器的validateExistingTransaction属性设置为true。这样当加入到一个隔离级别与内层事务完全不同的外层事务中时该加入操作会被拒绝。在该设置下如果read-write内层事务想要加入到外层的read-only事务中时该加入操作也会被拒绝。
- 在事务传播行为被设置为PROPAGATION_REQUIRED的情况下会为每个被设置事务的方法创建一个逻辑的事务作用域。各个逻辑事务作用域之间都是相互独立的在不同逻辑事务作用域之间都可以独立设置事务的rollback-only属性。但是在PROPAGATION_REQUIRED的情况下内层事务和外层事务都映射到同一个物理事务内层事务加入到外层事务中故而在内层逻辑事务中为物理事务设置rollback-only会切实影响到外层事务的提交。
- 当事务传播行为被设置为PROPAGATION_REQUIRED时如果内层事务设置了rollback-only标记那么会导致外层物理事务的回滚。当外层事务尝试提交并失败回滚后会抛出一个UnexceptedRollbackException异常外层事务commit方法的调用者会接受到该UnexceptedRollbackException代表内层发生了非预期的回滚操作
- ### PROPAGATION.REQUIRES_NEW
- 相对于PROPAGATION_REQUIREDPROPAGATION.REQUIRES_NEW传播行为会一直使用独立的物理事务而不会尝试区加入外部已经存在的物理事务。
- 对于PROPAGATION_NEW,其内层事务和外层事务都可以独立的提交或回滚,内层事务的回滚并不会导致外层事务的回滚。
- 将事务传播行为设置为PROPAGATION.REQUIRES_NEW时内层事务可以独立定义自己的隔离级别、timeout值、read-only属性而不必继承外部事务的这些属性。在PROPAGATION_REQUIRED中内部事务自定义这些属性将会被忽略内部事务加入外部事务后会采用外部事务的设置。
- ### PROPAGATION.NESTED
- 和PROPAGATION_REQUIRED类似PROPAGATION_NESTED同样也只有一个物理事务。但是其支持多个savepoint存档点该物理事务可以回滚到特定的存档点而非必须回滚整个事务。
- 由于PROPAGATION_NESTED对存档点的支持故而在PROPAGATION_NESTED条件下可以进行部分回滚。内层事务的回滚操作并不会造成外部事务的回滚内层事务回滚后外层事务仍然能够继续执行和提交。
> 由于PROPAGATION_NESTED需要JDBC savepoint存档点的支持故而该设置仅仅对JDBC事务资源有效。
> 当事务被回滚之后,当前事务无法再被提交,故而:
> 若在子事务中已经回滚子事务传播行为为required那么父事务的状态已经被回滚即使父事务捕获子事务抛出的异常那么在捕获异常之后执行的sql操作也不会被提交到数据库中父事务状态处于已回滚无法再次提交
> ***但是当子事务传播行为为nested时子事务虽然和父事务共用一个事务子事务回滚时只会回滚到子事务开启之前的存档点父事务在捕获子事务抛出异常之后执行的sql语句仍然可以被提交***

File diff suppressed because it is too large Load Diff