目前刚好在学习AOP,浅谈一下自己的部分理解
一.对AOP的理解
AOP,一般称为面向切面编程,作为面向对象(OOP)的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可复用的模块,这个模块被命名为“切面”(Aspect)。
SpringAOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
编程中,对象与对象之间,方法与方法之间,模块与模块之间都是一个个切面。
二.AOP专业术语
- 连接点(JoinPoint) : 用户可以被扩展的方法—>就是spring允许通知使用的地方,每个方法的前、后或两者都有以及抛出异常的地方都可以是连接点。
- 切入点(Pointcut): 用户实际扩展的方法—>在连接点的基础上定义切入点,如在一个类中有众多连接点,但是需要只是在其中几个连接点的前后或出现异常的地方干点事情,就需要用切入点定义几个方法来筛选的连接点,选中需要的方法
- 通知(Advice): 扩展方法的具体实现—>就是想要的功能,事物、日志等
- 切面(Aspect): 将通知应用到切入点的过程—>就是通知和切入点的结合。通知说明了干什么和什么时候干,而切入点就是说明了在哪干。
切面 = 切入点表达式 + 通知方法 - 代理(proxy): AOP机制都是通过代理,主要分为JDK动态代理、CGLib动态代理。
切入点表达式:
- bean(“对象的Id”)
@Pointcut(“bean(userServiceImpl)”)只匹配ID为userServiceImpl的对象 - within(“包名.类名”)
@Pointcut(“within(com.jt.demo2.service.*)”)匹配包路径为(com.jt.demo2.service)下的所有对象 - execution(返回值类型 包名.类名.方法名(参数列表))
@Pointcut(“execution(* com.jt.demo2.service..(…))”)
“*” 的含义:拦截返回值类型任意 xx.xx.service 包下所有子孙包的所有类的任意方法 - @annotation(注解的包路径)
@Pointcut("@annotation(com.jt.demo2.anno.find)")拦截xx包下的find的注解
例:自定义注解:
定义注解:
@Target(ElementType.METHOD) //注解在方法上使用/注解对方法有效
@Retention(RetentionPolicy.RUNTIME)//注解在运行期有效
public @interface Find {
int id() default 0;
}
使用注解:
@Find(id = 101)
通知方法:
- 前置通知 在目标方法执行之前执行.
- 后置通知 在目标方法执行之后执行.
- 异常通知 在目标方法执行之后抛出异常时执行.
- 最终通知 都要执行的通知
说明: 上述的四大通知一般用于记录程序的运行状态.只做记录 - 环绕通知 在目标方法执行前后都要执行的通知
记录程序的状态:
- 目标对象的class/类路径
- 目标对象的方法名
- 目标对象的方法的参数信息
- 获取目标对象方法的返回值
- 获取目标对象执行报错的异常信息
前置通知:
@Before("pointCut()")
public void before(JoinPoint joinPoint){
//1.获取目标对象的类型
Class targetClass = joinPoint.getTarget().getClass();
//2.获取目标对象的路径
String path = joinPoint.getSignature().getDeclaringTypeName();
//3.获取目标对象的方法名称
String methodname = joinPoint.getSignature().getName();
//4.获取方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("类型:"+targetClass);
System.out.println("路径:"+path);
System.out.println("方法名:"+methodname);
System.out.println("参数:"+ Arrays.toString(args));
}
后置通知
@AfterReturning(value = "pointCut()",returning = "result")
public void afterReturn(JoinPoint joinPoint,Object result){
//如果需要获取当前的方法信息,则可以通过joinPoint获取
System.out.println("我是后置通知,获取方法的返回值:"+result);
}
异常通知
@AfterThrowing(value = "pointCut()",throwing = "exception")
public void afterThrow(JoinPoint joinPoint,Exception exception){
//打印异常
//exception.printStackTrace();
System.out.println("我是异常通知:"+ exception.getMessage());
}