📜  Spring AOP AspectJ注释示例

📅  最后修改于: 2020-12-04 07:53:48             🧑  作者: Mango

Spring AOP AspectJ注释示例

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

有两种使用Spring AOP AspectJ实现的方法:

  • 通过注释:我们将在这里学习。
  • 通过xml配置(基于模式):我们将在下一页中学习它。

要了解aop概念及其优势等,请访问此处。AOP概念教程

Spring AspectJ AOP实现提供了许多注释:

  • @Aspect将类声明为方面。
  • @Pointcut声明切入点表达式。

用于创建建议的注释如下:

  • @Before声明之前的建议。在调用实际方法之前应用它。
  • @After声明事后建议。它在调用实际方法之后并返回结果之前应用。
  • @AfterReturning声明返回建议之后。在调用实际方法之后并返回结果之前应用。但是您可以在建议中获得结果值。
  • @Around声明了周围的建议。它在调用实际方法之前和之后应用。
  • @AfterThrowing声明throws建议。如果实际方法抛出异常,则将其应用。

了解切入点

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

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

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

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

了解切入点表达式

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

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

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

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

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

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

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

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

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

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

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

1)@之前的例子

在实际业务逻辑方法之前应用AspectJ Before Advice。您可以在此处执行任何操作,例如转换,身份验证等。

创建一个包含实际业务逻辑的类。

package com.javatpoint;
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;}
}

现在,创建包含在建议之前的方面类。

package com.javatpoint;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TrackOperation{
    @Pointcut("execution(* Operation.*(..))")
    public void k(){}//pointcut name
    
    @Before("k()")//applying pointcut on before advice
    public void myadvice(JoinPoint jp)//it is advice (before advice)
    {
        System.out.println("additional concern");
        //System.out.println("Method Signature: "  + jp.getSignature());
    }
}

现在创建定义bean的applicationContext.xml文件。





        
    
    
    
        

现在,让我们调用实际方法。

package com.javatpoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test{
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Operation e = (Operation) context.getBean("opBean");
        System.out.println("calling msg...");
        e.msg();
        System.out.println("calling m...");
        e.m();
        System.out.println("calling k...");
        e.k();
    }
}

输出量

  1. calling msg...  
  2. additional concern  
  3. msg() method invoked  
  4. calling m...  
  5. additional concern  
  6. m() method invoked  
  7. calling k...  
  8. additional concern  
  9. k() method invoked  

如您所见,在调用msg(),m()和k()方法之前,需要打印其他一些问题。

现在,如果您更改切入点表达式,如下所示:

  1. @Pointcut("execution(* Operation.m*(..))")  

现在,在操作类中以m开头的方法将引起更多关注。输出将如下所示:

  1. calling msg...  
  2. additional concern  
  3. msg() method invoked  
  4. calling m...  
  5. additional concern  
  6. m() method invoked  
  7. calling k...  
  8. k() method invoked  

现在您可以看到在调用k()方法之前未打印其他问题。

2)@之后的例子

调用实际的业务逻辑方法后,将应用忠于建议的AspectJ。它可以用来维护日志,安全性,通知等。

在这里,我们假设Operation.javaapplicationContext.xmlTest.java文件与@Before示例中给出的文件相同。

创建包含后建议的方面类。

package com.javatpoint;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TrackOperation{
    @Pointcut("execution(* Operation.*(..))")
    public void k(){}//pointcut name
    
    @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());
    }
}

输出量

  1. calling msg...  
  2. msg() method invoked  
  3. additional concern  
  4. calling m...  
  5. m() method invoked  
  6. additional concern  
  7. calling k...  
  8. k() method invoked  
  9. additional concern  

您可以看到在调用msg(),m()和k()方法之后,还会显示其他问题。

3)@AfterReturning示例

通过在返回建议后使用,我们可以在建议中获得结果。

创建包含业务逻辑的类。

package com.javatpoint;
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;}
}

返回建议后,创建包含的方面类。

package com.javatpoint;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

@Aspect
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...");
    }
}

与@Before建议示例中给出的相同

现在,创建调用实际方法的Test类。

package com.javatpoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test{
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Operation e = (Operation) context.getBean("opBean");
        System.out.println("calling m...");
        System.out.println(e.m());
        System.out.println("calling k...");
        System.out.println(e.k());
    }
}

输出量

  1. calling m...  
  2. m() method invoked  
  3. additional concern  
  4. Method Signature: int com.javatpoint.Operation.m()  
  5. Result in advice: 2  
  6. end of after returning advice...  
  7. 2  
  8. calling k...  
  9. k() method invoked  
  10. additional concern  
  11. Method Signature: int com.javatpoint.Operation.k()  
  12. Result in advice: 3  
  13. end of after returning advice...  
  14. 3  

您可以看到返回值被打印了两次,一次是由TrackOperation类打印的,第二次是由Test类打印的。

4)@周围的例子

围绕建议的AspectJ在调用实际的业务逻辑方法之前和之后都会应用。

在这里,我们假设applicationContext.xml文件与@Before示例中给出的文件相同。

创建一个包含实际业务逻辑的类。

package com.javatpoint;
public  class Operation{
    public void msg(){System.out.println("msg() is invoked");}
    public void display(){System.out.println("display() is invoked");}
}

创建包含建议周围的方面类。

您需要在advice方法中传递PreceedingJoinPoint引用,以便我们可以通过调用progress()方法来进行请求。

package com.javatpoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
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;
    }
}

现在,创建调用实际方法的Test类。

package com.javatpoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test{
    public static void main(String[] args){
        ApplicationContext context = new classPathXmlApplicationContext("applicationContext.xml");
        
        Operation op = (Operation) context.getBean("opBean");
        op.msg();
        op.display();
    }
}

输出量

  1. Additional Concern Before calling actual method  
  2. msg() is invoked  
  3. Additional Concern After calling actual method  
  4. Additional Concern Before calling actual method  
  5. display() is invoked  
  6. Additional Concern After calling actual method  

您可以看到在调用msg()和display方法之前和之后都会打印出其他问题。

5)@AfterThrowing示例

通过使用引发建议后的用法,我们可以在TrackOperation类中print异常。让我们看一下AspectJ AfterThrowing建议的示例。

创建包含业务逻辑的类。

package com.javatpoint;
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");
    }
    }
    
}

在抛出建议后,创建包含的方面类。

在这里,我们还需要传递Throwable引用,以便我们可以在此处拦截异常。

package com.javatpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
@Aspect
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("Exception is: "+error);
        System.out.println("end of after throwing advice...");
    }
}

与@Before建议示例中给出的相同

现在,创建调用实际方法的Test类。

package com.javatpoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test{
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Operation op = (Operation) context.getBean("opBean");
        System.out.println("calling validate...");
        try{
            op.validate(19);
        }catch(Exception e){System.out.println(e);}
        System.out.println("calling validate again...");
        
        try{
            op.validate(11);
        }catch(Exception e){System.out.println(e);}
    }
}

输出量

  1. calling validate...  
  2. Thanks for vote  
  3. calling validate again...  
  4. additional concern  
  5. Method Signature: void com.javatpoint.Operation.validate(int)  
  6. Exception is: java.lang.ArithmeticException: Not valid age  
  7. end of after throwing advice...  
  8. java.lang.ArithmeticException: Not valid age