【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;匹配特定方法的执行。

  1. AspectJ 5表达式:
//[]表示可选项;
//<>表示必选项。
execution([权限修饰符]<返回类型>[全限定类名.]<方法>(<参数>)[异常])
-每个部分都可以用*表示
-全限定类名:.*表示包中所有类,..*表示当前包与子包中的所有类。
-参数列表:
()表示方法无参数
(..)表示有任意个参数
(*)表示有一个任意类型的参数
(String)表示有一个String类型参数
(String,String)表示有2String类型参数

//举例:
execution(public com.luo.test.User.add(..))  //User类add方法
execution(* com.luo.test.User.*(..))   //所有方法
execution(* com.luo.test.*(..))   //所有类
execution(* com.luo.test.DeptService+)  //表示接口的所有方法以及实现了该接口的所有方法都被aop代理
  1. 使用&&、||、!、三种运算符来组合切点表达式,表示与或非的关系。

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方法的调用如果不是通过代理对象调用,那么不会生效。