Spring AOP AspectJ

Spring框架建议您AOP实现上使用Spring AspectJ AOP实现,因为它为您提供了更多的控制并且易于使用。

有两种方式可以实现Spring AOP AspectJ:

  • 基于注解(下面我们将讨论)
  • 基于xml配置

Spring AspectJ AOP 实现提供了很多注解:

  • @Aspect 声明一个切面类
  • @Pointcut 声明一个切点表达式

用于创建advices的注解如下:

  • @Before 声明一个before advice,它应用在实际方法调用之前
  • @After 声明一个after advice,它应用在实际方法调用之后
  • @AfterReturning 声明一个after returning advice,它应用在实际方法返回之后
  • @Around 声明一个around advice,它应用在实际方法调用前后
  • @AfterThrowing 声明一个 after throwing advice,它应用在实际方法抛出异常后

理解Pointcut(切入点)

切入点是Spring AOP的一种表达语言。

@Pointcut批注用于定义切入点。我们也可以通过名称引用切入点表达式。让我们看一下切入点表达式的简单示例。

@Pointcut("execution(* Operation.*(..))")  
private void doSomething() {}  

切入点表达式的名称为doSomething()。无论返回类型如何,它将应用于Operation类的所有方法。

了解切入点表达式

让我们尝试通过以下示例了解切入点表达式:

 @Pointcut("execution(public * *(..))")  

它将应用于所有公共方法。

@Pointcut("execution(public Operation.*(..))")  

它将应用于Operation类的所有公共方法。

@Pointcut("execution(public Employee.set*(..))")  

它将应用于Employee类的所有公共setter方法。

@Pointcut("execution(int Operation.*(..))")  

它将应用于返回int值的Operation类的所有方法。

1、@Before 例子

目录结构如下:

在实际业务逻辑方法之前应用AspectJ Before Advice。您可以在此处执行任何操作,例如conversion,authentication 等。创建一个包含实际业务逻辑的类。


import org.springframework.stereotype.Component;

/**
* @author:crelle
* @className:Operation
* @version:1.0.0
* @date:2020/9/21
* @description:XX
**/

@Component(value = "beforeOperation")
public class Operation {

public void msg(){
System.out.println("msg method invoked");
}

public int m(){
System.out.println("m method invoked");return 2;
}

public int k(){
System.out.println("k method invoked");return 3;
}
}

现在,创建aspect类并且包含before advice。


package crelle.test.aspectj.before;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
* @author:crelle
* @className:TrackOperation
* @version:1.0.0
* @date:2020/9/21
* @description:XX
**/
@Aspect
@Component(value = "beforeTrackOperation")
public class TrackOperation {

/**
*@author:crelle
*@date:2020/9/21
*@title:k
*@description:pointcut name
*@params:[]
*@return:void
*@throw:
*/
@Pointcut("execution(* crelle.test.aspectj.before.Operation.*(..))")
public void k(){};

/**
*@author:crelle
*@date:2020/9/21
*@title:myadvice
*@description: applying pointcut on before advice
*@params:[jp]
*@return:void
*@throw:
*/
@Before("k()")
public void myadvice(JoinPoint jp){
System.out.println("additional concern");
System.out.println("Method Signature:"+jp.getSignature());
}
}
 
import crelle.test.aspectj.before.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringAopAspectjAnnotationExampleApplication implements CommandLineRunner {

    @Autowired
    private Operation operation;

    public static void main(String[] args) {
        SpringApplication.run(SpringAopAspectjAnnotationExampleApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

     System.out.println("calling msg...");
       operation.msg();
       System.out.println("calling m...");
       operation.m();
       System.out.println("calling k...");
       operation.k();


    }
}

结果:

calling msg...
additional concern
Method Signature:void crelle.test.aspectj.before.Operation.msg()
msg method invoked
calling m...
additional concern
Method Signature:int crelle.test.aspectj.before.Operation.m()
m method invoked
calling k...
additional concern
Method Signature:int crelle.test.aspectj.before.Operation.k()
k method invoked

2、@After 例子

它可以用来维护log,security,notification 等。

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:Operation
 * @version:1.0.0
 * @date:2020/9/21
 * @description:XX
 **/
@Component(value = "afterOperation")
public class Operation {

    public void msg(){
        System.out.println("msg method invoked");
    }

    public int m(){
        System.out.println("m method invoked");return 2;
    }

    public int k(){
        System.out.println("k method invoked");return 3;
    }
}

现在,创建aspect类并且包含after advice。

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:TrackOperation
 * @version:1.0.0
 * @date:2020/9/21
 * @description:XX
 **/
@Aspect
@Component(value = "afterTrackOperation")
public class TrackOperation {

    @Pointcut("execution(* Operation.*(..))")
    public void k() {
    }

    @After("k()")//applying pointcut on after advice
    public void myadvice(JoinPoint jp)//it is advice (after advice)
    {
        System.out.println("additional concern");
        //System.out.println("Method Signature: "  + jp.getSignature());
    }
}
package crelle.test.aspectj;

import crelle.test.aspectj.after.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringAopAspectjAnnotationExampleApplication implements CommandLineRunner {

    @Autowired
    private Operation operation;

    public static void main(String[] args) {
        SpringApplication.run(SpringAopAspectjAnnotationExampleApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("calling msg...");
        operation.msg();
        System.out.println("calling m...");
        operation.m();
        System.out.println("calling k...");
        operation.k();

    }
}

结果:

calling msg...
msg method invoked
additional concern
calling m...
m method invoked
additional concern
calling k...
k method invoked
additional concern

3、@AfterReturning 例子

通过@AfterReturning,我们可以在advice中获得结果。

import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:Operation
 * @version:1.0.0
 * @date:2020/9/21
 * @description:XX
 **/
@Component(value = "afterreturningOperation")
public class Operation {

    public int m(){
        System.out.println("m() method invoked");
        return 2;
    }
    public int k(){
        System.out.println("k() method invoked");
        return 3;
    }
}

现在,创建aspect类并且包含afterreturning advice。

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:TrackOperation
 * @version:1.0.0
 * @date:2020/9/21
 * @description:XX
 **/
@Aspect
@Component(value = "afterreturningTrackOperation")
public class TrackOperation{

    @AfterReturning(pointcut = "execution(* Operation.*(..))",returning= "result")
    public void myadvice(JoinPoint jp, Object result)//it is advice (after returning advice)
        {
            System.out.println("additional concern");
            System.out.println("Method Signature: " + jp.getSignature());
            System.out.println("Result in advice: "+result);
            System.out.println("end of after returning advice...");
        }
}
package crelle.test.aspectj;

import crelle.test.aspectj.afterreturning.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringAopAspectjAnnotationExampleApplication implements CommandLineRunner {

    @Autowired
    private Operation operation;

    public static void main(String[] args) {
        SpringApplication.run(SpringAopAspectjAnnotationExampleApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {

        System.out.println("calling m...");
        System.out.println(operation.m());
        System.out.println("calling k...");
        System.out.println(operation.k());


    }
}

结果:

calling m...
m() method invoked
additional concern
Method Signature: int crelle.test.aspectj.afterreturning.Operation.m()
Result in advice: 2
end of after returning advice...
2
calling k...
k() method invoked
additional concern
Method Signature: int crelle.test.aspectj.afterreturning.Operation.k()
Result in advice: 3
end of after returning advice...
3

4、@Around 例子

around advice的AspectJ在调用实际的业务逻辑方法之前和之后都会应用。

import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:Operation
 * @version:1.0.0
 * @date:2020/9/21
 * @description:XX
 **/
@Component(value = "aroundOperation")
public class Operation {

    public void msg(){
        System.out.println("msg() is invoked");
    }
    public void display(){
        System.out.println("display() is invoked");
    }
}

现在,创建aspect类并且包含around advice。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:TrackOperation
 * @version:1.0.0
 * @date:2020/9/21
 * @description:XX
 **/
@Aspect
@Component(value = "aroundTrackOperation")
public class TrackOperation {
    @Pointcut("execution(* Operation.*(..))")
    public void abcPointcut() {
    }

    @Around("abcPointcut()")
    public Object myadvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Additional Concern Before calling actual method");
        Object obj = pjp.proceed();
        System.out.println("Additional Concern After calling actual method");
        return obj;
    }
}
package crelle.test.aspectj;

import crelle.test.aspectj.around.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringAopAspectjAnnotationExampleApplication implements CommandLineRunner {

    @Autowired
    private Operation operation;

    public static void main(String[] args) {
        SpringApplication.run(SpringAopAspectjAnnotationExampleApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        operation.msg();
        operation.display();

    }
}

结果:

Additional Concern Before calling actual method
msg() is invoked
Additional Concern After calling actual method
Additional Concern Before calling actual method
display() is invoked
Additional Concern After calling actual method

5、@AfterThrowing 例子

通过使用@AfterThrowing,我们可以在TrackOperation类中打印异常。让我们看一下AspectJ AfterThrowing advice的示例。

import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:Operation
 * @version:1.0.0
 * @date:2020/9/21
 * @description:XX
 **/
@Component(value = "afterthrowingOperation")
public class Operation {

    public void validate(int age)throws Exception{
        if(age<18){
            throw new ArithmeticException("Not valid age");
        }else{
            System.out.println("Thanks for vote");
        }
    }
}

现在,创建aspect类并且包含after throwing advice。

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
 * @author:crelle
 * @className:TrackOperation
 * @version:1.0.0
 * @date:2020/9/21
 * @description:XX
 **/
@Aspect
@Component(value = "afterthrowingTrackOperation")
public class TrackOperation {

    @AfterThrowing(
            pointcut = "execution(* Operation.*(..))",
            throwing= "error")
    public void myadvice(JoinPoint jp, Throwable error)//it is advice
    {
        System.out.println("additional concern");
        System.out.println("Method Signature: "  + jp.getSignature());
        System.out.println("Method params:" + jp.getArgs().toString());
        System.out.println("Exception is: "+error);
        System.out.println("end of after throwing advice...");
    }
}
package crelle.test.aspectj;

import crelle.test.aspectj.afterthrowing.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class SpringAopAspectjAnnotationExampleApplication implements CommandLineRunner {

    @Autowired
    private Operation operation;

    public static void main(String[] args) {
        SpringApplication.run(SpringAopAspectjAnnotationExampleApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        try{
            operation.validate(19);
        }catch(Exception e){
            System.out.println(e);
        }

         System.out.println("calling validate again...");

        try{
            operation.validate(11);
        }catch(Exception e){
            System.out.println(e);
        }

    }
}

结果:

Thanks for vote
calling validate again...
additional concern
Method Signature: void crelle.test.aspectj.afterthrowing.Operation.validate(int)
Method params:[Ljava.lang.Object;@6bb2d00b
Exception is: java.lang.ArithmeticException: Not valid age
end of after throwing advice...
java.lang.ArithmeticException: Not valid age

完毕!

原文地址:https://www.cnblogs.com/crelle/p/13709149.html