Aop:面向切面编程,即是横向重复、纵向抽取思想。
springAop:底层封装了动态代理和cglib代理的代码,我们不需要手写动态代理的代码,封装的两个代理可以对任何类进行增强。
使用Aop的注意事项/坑:
1)、不宜把重要业务放在Aop中处理。
2)、Aop不处理Static、final、private方法
3)、无法拦截内部方法调用
spring名词:
1)连接点(JoinCut):目标对象中所有可以增强的方法,可以认为是类中的所欲方法
2)切入点(PointCut):目标对象中需要对它进行增强的方法
3)切面(Aspect):切入点+通知
4)织入(Weaving):将通知织入到切入点的过程叫做织入
5)目标对象(Target):即是需要增强的类
6)代理(Proxy):将通知织入到目标对象之后生成代理对象
7)通知/增强(Advice):对切入点所增强的代码
通知类型:
前置通知:(在调用目标对象之前执行)
环绕通知:(在目标对象调用之前和调用之后都会执行)
异常通知:(在调用目标对象之后执行)
后置通知(出现异常也会执行):(在调用目标对象之后异常情况下也会执行)
后置通知(出现异常不会执行):(在调用目标对象之后异常情况下不会执行)
springBoot整合Aop实例介绍
1、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、设置方法接口
package com.ltj.demo.Service.Interface;
/**
* 接口测试类
*/
public interface interfaceA {
//增加
public String save(int args1,int args2);
}
3、实现接口
package com.ltj.demo.Service;
import com.ltj.demo.Service.Interface.interfaceA;
import org.springframework.stereotype.Service;
/**
* 设置通知
*/
@Service
public class interfaceAImpl implements interfaceA {
@Override
public String save(int mathScore,int engScore) {
System.out.println("保存成功");
System.out.println("the total score is : " + mathScore+engScore);
return "保存成功22";
}
}
4、设置通知类
package com.ltj.demo.Service;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 通知/增强名词
* 前置通知(在调用目标对象之前执行)
* 后置通知(异常情况下不会执行)
* 环绕通知(在目标对象调用之前和调用之后都会执行)
* 异常通知(在调用目标对象之后执行)
* 后置通知(异常情况下也会执行)
*/
/**
* @Aspect:该注解设置该类为切面
* @Component
*/
@Aspect
@Component
public class MyAdvice {
//设置方法作为切入点
@Pointcut(value = "execution(* com.ltj.demo.Service.interfaceAImpl.*(..))")
public void pointCut(){}
//设置前置通知
@Before("MyAdvice.pointCut()")
public void before(JoinPoint joinPoint){
Object[] obj = joinPoint.getArgs(); //获取连接点方法运行时的入参列表
String methodName = joinPoint.getSignature().getName();
Object paramter1 = joinPoint.getSignature().getDeclaringType();
Object paramter2 = joinPoint.getSignature().getDeclaringTypeName();
Object paramter3 = joinPoint.getSignature().getModifiers();
System.out.println(methodName); //获取目标对象的方法名
System.out.println(paramter1);
System.out.println(paramter2);
System.out.println(paramter3);
System.out.println(joinPoint.getThis()); //获取代理对象本身
System.out.println(joinPoint.getTarget()); //获取连接点所在的目标对象
for (Object objs: obj) { //循环获取入参值
System.out.println("入参:" + objs);
}
System.out.println("我是前置通知");
}
/**
* 设置后置通知(异常情况下也会执行)
* @param joinPoint 目标类连接点对象
*/
@After("MyAdvice.pointCut()")
public void after(JoinPoint joinPoint){
System.out.println("设置后置通知(异常情况下也会执行)");
}
//设置后置通知(异常情况下不会执行)
@AfterReturning(value="MyAdvice.pointCut()", returning ="results") //value设置切入点,results为返回值
public void afterReturn(JoinPoint joinPoint,Object results){ //results设置参数接收返回值
System.out.println("设置后置通知(异常情况下不会执行)");
System.out.println("返回值为:" + results); //输出results返回值,即是目标对象的返回值
}
/**
* 设置异常通知
* @param proceedingJoinPoint JoinPoint的子接口
*/
@AfterThrowing("MyAdvice.pointCut()")
public void afterThrow(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("我是异常通知");
}
/**
* 设置环绕通知
* @param proceedingJoinPoint JoinPoint的子接口
*/
@Around("MyAdvice.pointCut()")
public void around(ProceedingJoinPoint proceedingJoinPoint){
String methodName = proceedingJoinPoint.getSignature().getName();
Object result = null;
try {
System.out.println("我是环绕通知");
result = proceedingJoinPoint.proceed(); //通过反射执行目标对象的连接点处的方法
System.out.println("环绕通知的名称为:" + methodName +
",返回的执行结果是:" + result);
}catch (Throwable throwable){
throwable.printStackTrace();
System.out.println("异常返回");
}
}
}
5、使用测试类进行测试
package com.ltj.demo.Service;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.*;
@SpringBootTest
@RunWith(SpringRunner.class)
public class interfaceAImplTest {
//自动注入
@Autowired
interfaceAImpl interfaceAImp;
@Test
public void example() {
//调用保存方法
interfaceAImp.save(1,2);
}
}
友情链接:
AspectJ JoinPoint及ProceedingJoinPoint 简要api文档:https://blog.csdn.net/airjordon/article/details/83623830
SpringBoot集成ApringAOP:https://www.cnblogs.com/zdj-/p/8665454.html
springAop视同注解实现5种通知类型:https://www.cnblogs.com/fengxiangyu/p/10896547.html