Spring AOP
1.转账案例中的事务问题
图中每一个操作都有一个connection,程序无错,就提交,但是回滚各操作间不影响。
所以要使用ThreadLocal对象把Connction和当前线程绑定,从而使一个线程中只有一个类控制事务的对象。
2.动态代理
2.1概念及其作用:
动态代理:是使用反射和字节码的技术,在运行期创建指定接口或类的子类,以及其实例对象的技术,通过这个技术可以无侵入的为代码进行增强
2.2特点:
字节码随用随创建,随用随加载
2.3分类
2.3.1基于接口的动态代理
涉及的类:proxy
提供者:jdk官方
步骤
1.创建代理对象
使用proxy类中的newProxyInstance方法
2.创建代理对象的要求
被代理类至少实现一个接口,没有则不能使用
3.newProxyInstance方法的参数
Loader:类加载器
用于加载动态代理对象的字节码,写的是和被代理对象相同的类加载器。固定写法
Class[]:字节码数组
让代理对象和被代理对象有相同的方法。
invocationHandler:
代理内容,一般情况下写一个该接口的实现类,一般是匿名内部类,此接口的实现类谁用谁写。
2.3.2基于子类的动态代理
设计的类:Enhancer
提供者:第三方cglib库
步骤
1.创建代理对象
使用Enhancer的create方法
2.创建代理对象的要求
被代理的类不能是最终类
3.create方法的参数
Class字节码:
用于指定被代理对象的字节码
Callback:用于提供被增强的代码
代理内容,一般情况下写一个该接口的实现类,一般是匿名内部类,此接口的实现类谁用谁写。我们一般用该接口的子接口实现类:MethodInterceptor
3.AOP面向切面编程
3.1.Aop概念:
是通过预编译的方式和运行期间动态代理实现程序功能的统一维护的一种技术。简单的说就是把我们重复的代码抽取出来,在需要执行的时候,使用动态代理技术,在不修改源码的基础上,对我们的已有方法进行增强
3.2aop相关术语:
Joinpoint(连接点):
所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。 所有的方法都叫连接点
Pointcut(切入点):
所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。被增强的方法叫切入点。
Advice(通知/增强):
所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):
引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。
Target(目标对象):
代理的目标对象。
Weaving(织入):
是指把增强应用到目标对象来创建新的代理对象的过程。
spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
Proxy(代理):
一个类被 AOP 织入增强后,就产生一个结果代理类。
Aspect(切面):
是切入点和通知(引介)的结合。
3.3spring基于aop的配置
1.把通知的bean交给spring来管理
2.使用aop:config标签表明开始aop的配置
3.使用aop:aspect标签表面开始切面的配置
id属性:是给切面提供一个唯一标识
ref属性:是指定通知类bean的id
4.在aop:aspect标签的内部使用对应标签来配置通知的类型
1.aop:before标签: 表示配置前置通知
method属性: 用于指定Logger类中哪个方法是前置通知
poincut属性: 用于指定切入点表达式,该表达式的含义指的是对业务层中哪些3方法进行增强
3.4 切入点表达式的写法:
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)
标准的表达式写法:
public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
void com.itheima.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,表示任意返回值
* com.itheima.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* ....AccountServiceImpl.saveAccount())
包名可以使用…表示当前包及其子包
* …AccountServiceImpl.saveAccount()
类名和方法名都可以使用来实现通配
* ….()
参数列表:
可以直接写数据类型:
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用…表示有无参数均可,有参数可以是任意类型
全通配写法:
* ….(…)
实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法
* com.itheima.service.impl.*.*(..)
3.5AOP通知
1、前置通知:在切入点方法之前执行
2、后置通知:在切入点方法之后通知
3、异常通知:在执行切入点方法过程中出现异常后执行(因此异常通知和后置通知只能执行一个)
4、最终通知:无论切入点方法是否正常执行它都会执行
5、环绕通知: 当配置环绕通知之后,在环绕通知里面必须要明确调用业务层的方法,如果不调用,就会出现只出现通知,而不执行方法。。
Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
spring中的环绕通知:
它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
3.基于XML的AOP实现事务控制
在使用前后异环四种通知时,通知的顺序在spring5.0早期版本中会有bug,导致执行顺序不对
3.基于注解L的AOP实现事务控制
需要导入注解和aop的约束,最好用环绕通知,以免产生顺序bug。
4.Spring事务控制
4.1spring声明式事务
4.1.1spring基于xml的声明式事务控制
spring中基于XML的声明式事务控制配置步骤
1.配置事务管理器(事务中具体做的操作)
2.配置事务的通知
此时我们需要导入事务的约束,tx名称空间和约束,同时也需要aop的
使用tx:advice标签配置事务通知
属性:
id:事务通知唯一标识
transaction-manager:给 事务通知提供一个事务管理器bean
3.配置AOP中的通用切入点表达式
4.建立事务通知和切入点的表达关系
5.配置事务的属性
是在事务的通知tx:advice标签的内部
4.1.2spring基于注解的声明式事务控制
spring中基于注解的声明式事务控制 配置步骤
1.配置事务管理器
2.开启spring对注解事务的支持
3.在需要事务支持的地方使用@Transaction注解
4.2spring编程式事务控制
执行transactionTemplate的execute方法,创建 TransactionCallback内部类,重写doInTransaction方法
此方法重复代码多,一般不会用到