Spring AOP AspectJ注解示例

Spring框架建议您在基于Spring 1.2旧样式dtd的AOP实现上使用 Spring AspectJ AOP实现易于使用。

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

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

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

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

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

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

@Before 声明before建议。在调用实际方法之前将其应用。 @After 声明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、@Before示例

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

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

文件: Operation.java

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

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

文件: TrackOperation.java

package com.nhooo;
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()")//在before通知上应用切入点
	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文件。

文件: applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop" 
	   xsi:schemaLocation="http://www.springframework.org/schema/beans 
	   http://www.springframework.org/schema/beans/spring-beans.xsd 
	   http://www.springframework.org/schema/aop 
	   http://www.springframework.org/schema/aop/spring-aop.xsd">
	<bean id="opBean" class="com.nhooo.Operation">	</bean>
	<bean id="trackMyBean" class="com.nhooo.TrackOperation"></bean>
	
	<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"></bean>
		
</beans>

现在,让我们称为实际方法。

文件: Test.java

package com.nhooo;
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();
	}
}

输出

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

正如您看到的,在调用msg(),m()和k()方法之前,还会显示其他问题。

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

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

现在,将更加关注Operation类中以m开头的方法。输出将如下所示:

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

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


2、@After示例

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

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

文件: TrackOperation.Java
package com.nhooo;
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());
	}
}
 

输出

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

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


3、@AfterReturning示例

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

创建包含以下内容的类业务逻辑。

文件: Operation.java

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

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

文件: TrackOperation.java

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

文件: applicationContext.xml

与@Before建议示例中给出的

文件: Test.java

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

package com.nhooo;
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());
	}
}
 

输出

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

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


4、@Around示例

围绕通知的AspectJ在调用实际的业务逻辑方法之前和之后都得到应用。

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

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

文件: Operation.java

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

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

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

文件: TrackOperation.java

package com.nhooo;
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.java

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

package com.nhooo;
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();
	}
}
 

输出

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
 

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


5、@AfterThrowing示例

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

创建包含业务逻辑的类。

文件: Operation.java

package com.nhooo;
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引用,以便我们可以在此处拦截异常。

文件: TrackOperation.java

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

文件: applicationContext.xml

与@Before建议示例中给出的

文件: Test.java

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

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

输出

calling validate...
Thanks for vote
calling validate again...
additional concern
Method Signature: void com.nhooo.Operation.validate(int)
Exception is: java.lang.ArithmeticException: Not valid age
end of after throwing advice...
java.lang.ArithmeticException: Not valid age