AspectJ基本语法和意义

216 阅读3分钟

AspectJ是一种面向切面编程(AOP)语言,它可以用于在Java代码中定义和使用切面。下面是AspectJ的基本语法和意义:

下面是AspectJ的完整语法:

  1. 切面声明

切面声明用于定义一个切面类,其中包含切点和通知。切面类必须包含@Aspect注释。

@Aspect
public class MyAspect {
    // 切点和通知
}
  1. 切点

切点用于定义在何处应用通知。它可以是一个方法调用,一个字段访问,一个对象创建等等。

@Pointcut("execution(* com.example.MyClass.myMethod(..))")
public void myPointcut() {}

上面的代码定义了一个切点,它匹配com.example.MyClass类的myMethod方法。

  1. 通知

通知用于在切点匹配时执行某些代码。AspectJ支持五种类型的通知:

  • @Before:在方法执行前执行代码。
  • @After:在方法执行后执行代码,无论是否抛出异常。
  • @AfterReturning:在方法执行后执行代码,仅在方法成功返回时执行。
  • @AfterThrowing:在方法抛出异常时执行代码。
  • @Around:环绕通知,可以在方法执行前和执行后执行代码。
@Before("myPointcut()")
public void myBeforeAdvice() {
    // 在切点匹配时执行代码
}

上面的代码定义了一个@Before通知,它在myPointcut切点匹配时执行myBeforeAdvice方法。

  1. 连接点

连接点是在程序执行期间切点匹配的实际位置。例如,在方法调用连接点中,连接点是在方法被调用之前或之后。

@AfterReturning("myPointcut()")
public void myAfterReturningAdvice(JoinPoint joinPoint) {
    // 在方法成功返回后执行代码,并传递JoinPoint参数
}

上面的代码定义了一个@AfterReturning通知,它在myPointcut切点匹配时执行myAfterReturningAdvice方法,并传递JoinPoint参数,该参数包含有关连接点的信息。

  1. 切面优先级

如果有多个切面匹配同一个连接点,AspectJ将按照以下顺序执行它们的通知:

  • @Around
  • @Before
  • 按照声明顺序执行所有其他类型的通知
  • @AfterReturning和@AfterThrowing

可以使用@Order注释指定切面的优先级。

@Aspect
@Order(1)
public class MyAspect1 {
    // 切点和通知
}

@Aspect
@Order(2)
public class MyAspect2 {
    // 切点和通知
}

上面的代码定义了两个切面类,MyAspect1优先于MyAspect2。

  1. 切点函数

切点函数可以将切点表达式提取到单独的函数中,以便在多个通知和切面中重复使用。

@Pointcut("execution(* com.example.MyClass.myMethod(..))")
public void myPointcut() {}

@Pointcut("within(com.example.MyClass)")
public void myWithinPointcut() {}

@Pointcut("myPointcut() && myWithinPointcut()")
public void myCombinedPointcut() {}

上面的代码定义了三个切点函数,myPointcut匹配com.example.MyClass类的myMethod方法,myWithinPointcut匹配com.example.MyClass类中的所有方法,myCombinedPointcut同时匹配myPointcut和myWithinPointcut。

  1. 切点指示符

除了使用execution指示符定义切点外,AspectJ还支持其他指示符,例如call、get、set、handler、preinitialization等。

@Pointcut("call(* com.example.MyClass.myMethod(..))")
public void myCallPointcut() {}

@Pointcut("get(* com.example.MyClass.myField)")
public void myGetPointcut() {}

上面的代码定义了两个切点,myCallPointcut匹配对com.example.MyClass.myMethod方法的调用,myGetPointcut匹配对com.example.MyClass.myField字段的get访问。

  1. 参数绑定

通知可以使用参数绑定访问连接点和切点。

@Before("myPointcut() &&args(param1, param2)")
public void myBeforeAdvice(JoinPoint joinPoint, Object param1, int param2) {
    // 在切点匹配时执行代码,并传递JoinPoint参数和参数绑定值
}

上面的代码定义了一个@Before通知,它在myPointcut切点匹配时执行myBeforeAdvice方法,并传递JoinPoint参数和参数绑定值param1和param2。

  1. 引入

引入允许向现有类添加新功能或接口。

public interface MyInterface {
    void myMethod();
}

@Aspect
public class MyAspect {
    @DeclareParents(value = "com.example.MyClass", defaultImpl = MyInterfaceImpl.class)
    private MyInterface myInterface;
}

public class MyClass {
    // ...
}

public class MyInterfaceImpl implements MyInterface {
    public void myMethod() {
        // 添加新功能或接口
    }
}

上面的代码使用@DeclareParents注释将MyInterface添加到com.example.MyClass类中,并指定默认实现类MyInterfaceImpl。

  1. 注入

注入允许在运行时修改现有类的行为。

@Aspect
public class MyAspect {
    @Around("execution(* com.example.MyClass.myMethod(..))")
    public Object myAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 在方法执行前和执行后执行代码
        Object result = proceedingJoinPoint.proceed();
        // 修改返回值或抛出异常
        return result;
    }
}

上面的代码使用@Around注释定义一个环绕通知,它在com.example.MyClass.myMethod方法执行前和执行后执行代码,并可以修改返回值或抛出异常。

以上是AspectJ的基本语法和意义,它可以帮助开发人员在Java代码中实现切面编程。