发表于: 2020-06-19 22:14:54
1 1635
加油!!!
今天完成的事:
什么是 AOP
AOP 即面向切面编程,英文全称为 Aspect Oriented Programming
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
作用
在程序运行期间,不修改源码对已有方法进行增强。
优势
减少重复代码
提高开发效率
维护方便
Joinpoint (连接点)
所谓连接点是指那些被拦截到的方法
比如说,我们的业务层中的方法都是连接点,因为我们对业务层中的所有方法都进行了拦截
Pointcut (切入点)
所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义,简单来说就是被增强的方法
比如说,我们在业务层新增了一个方法 test() ,但是在代理工厂中,我们不对该方法进行增强,而是直接放行,那么此时的 test() 就不是切入点,仅仅是一个连接点,而其他的方法都被事务管理,也就是切入点
基于XML中AOP的配置步骤
1、使用 <bean> 标签将通知类配置进容器中
2、使用 <aop:config> 标签开始声明 AOP 配置
3、使用 <aop:aspect> 标签开始配置切面
4、在 <aop:aspect> 标签的内部使用对应标签来配置通知的类型
5、使用 <aop:pointcut> 标签配置切入点表达式
6、使用 <aop:xxx> 标签配置对应的通知类型
关于使用AOP对事务控制的配置
<!-- 配置事务管理器 -->
<bean id="txManager" class="com.ptt.utils.TransactionManager">
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<!-- 配置aop -->
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.ptt.service.*.*(..))"/>
<aop:aspect id="txAdvice" ref="txManager">
<!-- 前置通知:开启事务beginTransaction,在切入点方法执行之前执行-->
<aop:before method="beginTransaction" pointcut-ref="pt1"></aop:before>
<!-- 后置通知:提交事务commit,在切入点方法正常执行之后值。它和异常通知永远只能执行一个 -->
<aop:after-returning method="commit" pointcut-ref="pt1"></aop:after-returning>
<!-- 异常通知:回滚事务rollback,在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个 -->
<aop:after-throwing method="rollback" pointcut-ref="pt1"></aop:after-throwing>
<!-- 最终通知:释放连接release,无论切入点方法是否正常执行它都会在其后面执行 -->
<aop:after method="release" pointcut-ref="pt1"></aop:after>
<!-- <aop:around method="" pointcut-ref="pt1"></aop:around>-->
</aop:aspect>
</aop:config>
AOP中的环绕通知
环绕通知是 Spring 框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式,一般情况下都是单独使用的
在配置文件中使用 <aop:around> 来配置环绕通知
<!-- 配置aop -->
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.ptt.service.*.*(..))"/>
<aop:aspect id="txAdvice" ref="txManager">
<!-- 环绕通知-->
<aop:around method="aroundTransaction" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
编写环绕通知实现类
/**
* 环绕通知,一般单独使用
*/
public Object aroundTransaction(ProceedingJoinPoint proceedingJoinPoint) {
// 用于接收返回值
Object returnValue = null;
try {
// 获取切入点方法参数
Object[] args = proceedingJoinPoint.getArgs();
// 前置通知:开始事务
this.beginTransaction();
// 调用切入点方法
returnValue = proceedingJoinPoint.proceed(args);
// 后置通知:提交事务
this.commit();
} catch (Throwable throwable) {
// 异常通知:回滚事务
this.rollback();
throwable.printStackTrace();
} finally {
// 最终通知:释放连接
this.release();
}
return returnValue;
}
Spring中XML+注解方式的AOP配置
@Component("logger")
@Aspect//表示当前类是一个切面
public class Logger {
@Pointcut("execution(* com.ptt.service.*.*(..))")
private void pt1(){}
/**
* 前置通知
*/
@Before("pt1()")
public void beforePrintLog(){
System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。");
}
/**
* 后置通知
*/
@AfterReturning("pt1()")
public void afterReturningPrintLog(){
System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
}
/**
* 异常通知
*/
@AfterThrowing("pt1()")
public void afterThrowingPrintLog(){
System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
}
/**
* 最终通知
*/
@After("pt1()")
public void afterPrintLog(){
System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
}
/**
* 环绕通知,一般单独使用
*/
//@Around("pt1()")
public void aroundTransaction(ProceedingJoinPoint proceedingJoinPoint){
// System.out.println("环绕通知Logger类中的aroundTransaction方法开始记录日志了。。。");
// 用于接收返回值
Object returnValue = null;
try {
// 获取切入点方法参数
Object[] args = proceedingJoinPoint.getArgs();
// 前置通知:开始事务
this.beforePrintLog();
// 调用切入点方法
returnValue = proceedingJoinPoint.proceed(args);
// 后置通知:提交事务
this.afterReturningPrintLog();
} catch (Throwable throwable) {
// 异常通知:回滚事务
this.afterThrowingPrintLog();
throwable.printStackTrace();
} finally {
// 最终通知:释放连接
this.afterPrintLog();
}
}
关于其中的一些注解
@Aspect 注解用于将当前类声明为切面
@Pointcut 注解用于指定切入点表达式,其属性 value 指定表达式的内容
该注解只能作用在方法上
@Before 注解将当前方法声明为前置通知,其属性 value 既可以指定切入点表达式,也可以指定切入点表达式的引用
当引用切入点表达式的时候,写法为: @Before("pt1()"),要注意 () 不可以省略
@AfterReturning 注解将当前方法声明为后置通知
@AfterThrowing 注解将当前方法声明为异常通知
@After 注解将当前方法声明为最终通知
@Around 注解将当前方法声明为环绕通知通知
明天计划的事:
遇到的困难:
收获:
评论