【java学习】面向切面编程(AOP,Aspect Orient Programming)
1,AOP使用场景
面向对象编程(OOP)是从静态角度考虑程序结构,面向切面编程(AOP)是从动态角度考虑程序执行过程。
OOP是从上到下定义问题,AOP通过从左到右定义问题。将一些具有横切性质的系统性服务定义为一个切面,自动注入到目标对象即可统一处理。如事物管理、安全检查、缓存、对象池管理等。
1)优点
不修改原代码,就可以在主干功能里面添加新功能。
2,实现
AspectJ不是Spring组成部分,是独立的AOP框架,一般把AspectJ和Spring框架一起使用进行AOP操作。
常用注解:
注解 | 场景说明 | 备注 |
---|---|---|
@EnableAspectJAutoProxy | 开启Spring对AspectJ代理的支持 | |
@Aspect | 声明一个切面类 | |
@Order(数字) | 设定切面类的优先级。数字越小优先级越高,从0开始。 | |
@Pointcut | 声明切点 | |
@Before | 在切点方法之前执行 | 声明前置通知 |
@After | 在切点方法之后执行 | 声明后置通知 |
@AfterReturning | 切点方法返回后执行(发生异常就不会执行) | |
@AfterThrowing | 切点方法抛异常执行 | |
@Around | 属于环绕增强,能控制切点执行前、执行后 | 声明环绕通知 |
引入依赖:org.springframework:spring-aspects
1)切面类(aspect)
用@Aspect 声明,同时用@Component声明其是一个bean类。
注意:切面类不会被其他切面自动拦截。
切面(aspect)
按关注点进行模块分解时,横切关注点就表示为一个切面。
连接点(join point)
程序执行的某一刻,可以在这个点上添加额外的动作。
通知(advice)
切面在特定join point上执行的动作。
切入点(pointcut)
用来描述连接点的,它决定了当前代码与连接点是否匹配。
2)切入点(切点,point cut)
通过@Pointcut申明。
//公共切入点抽取
@Pointcut(value="切入点表达式")
public void pointDemo(){}
@Before(value="pointDemo()")
常用PCD(pointcut designator,切入点标识符):
1>execution
最常用PCD;匹配特定方法的执行。
- AspectJ 5表达式:
//[]表示可选项;
//<>表示必选项。
execution([权限修饰符]<返回类型>[全限定类名.]<方法>(<参数>)[异常])
-每个部分都可以用*表示
-全限定类名:.*表示包中所有类,..*表示当前包与子包中的所有类。
-参数列表:
()表示方法无参数
(..)表示有任意个参数
(*)表示有一个任意类型的参数
(String)表示有一个String类型参数
(String,String)表示有2个String类型参数
//举例:
execution(public com.luo.test.User.add(..)) //User类add方法
execution(* com.luo.test.User.*(..)) //所有方法
execution(* com.luo.test.*(..)) //所有类
execution(* com.luo.test.DeptService+) //表示接口的所有方法以及实现了该接口的所有方法都被aop代理
- 使用&&、||、!、三种运算符来组合切点表达式,表示与或非的关系。
2>within
匹配特定范围内的类型,可以用通配符匹配某个java包内所有的类。
@within
3>this
aop代理对象这个bean本身要匹配某个给定的类型
4>target
目标对象要匹配某个给定的类型。
@target
;
//目标类型为hello及其子类
target(learning.spring.helloworld.Hello+)
5>args
传入的方法参数要匹配某个给定的类型
@args
//方法的参数只有一个String
args(java.lang.String)
6>bean
匹配Bean的ID或名称,可以用通配符
7>@annotation
拦截的方法上有某个特定类型注解。
举例:自定义注解结合aop,不动原代码即可进行修改:
@Pointcut("@annotation(com.luo.handler.AuthRecord)")
public void pointcut() {
log.debug("进入切入点,开始构造日志...");
}
@AfterReturning(value = "pointcut() && @annotation(annotation)", returning = "result")
public void generateRecordByState(JoinPoint joinPoint , Object result, AuthRecord annotation) {
}
3)切入点增强处理
JoinPoint :方法中的参数JoinPoint为连接点对象,它可以获取当前切入的方法的参数、代理类等信息,因此可以记录一些信息,验证一些信息等;
//aop代理对象
Object aThis = joinPoint.getThis();
//被代理对象
Object target = joinPoint.getTarget();
3,底层原理
动态代理(GOF代理模式):运行时动态地为对象创建代理的技术。
一般采用:JDK动态代理、CGLIB动态代理。
JDK和CGLIB动态代理区别:
必须要实现接口 | 支持拦截public方法 | 直接拦截protected方法 | 支持默认作用域方法(非public protected private的方法) | |
---|---|---|---|---|
JDK动态代理 | 是 | 是 | 否 | 否 |
CGLIB动态代理 | 否 | 是 | 是 | 是 |
注意:aop方法的调用如果不是通过代理对象调用,那么不会生效。