1. Enabling AspectJ annotation support in Spring
-
1 To use AspectJ annotations in Spring applications, you must include AspectJ class libraries under classpath: aopalliance.jar, aspectj.weaver.jar, and spring-aspects.jar
maven Introduces<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.8</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.8</version> <scope>runtime</scope> </dependency>
- 2 Add aop Schema to the root element.
-
3 To enable AspectJ annotation support in the Spring IOC container, simply define an empty XML element in the Bean configuration file
<! -- Configuration automatically generates proxy objects for Java classes that match the aspectJ annotations - > < aop: aspectj-autoproxy > </aop: aspectj-autoproxy >
-
4 When the Spring IOC container detects elements in the Bean configuration file, it automatically creates proxies for beans that match AspectJ facets.
AspectJ supports five types of notification annotations:
- @Before Pre-notification, executed before method execution
- @ After: Post-notification, executed after method execution
- @ AfterRunning: Returns the notification and executes after the method returns the result
- @ AfterThrowing: Exception notification, after the method throws an exception
- @Around : around notification, around method execution
2.1. Use the previous calculator interface and implementation classes Arithmetic Calculator. java, Arithmetic Calculator Impl. Java
@Component("arithmeticCalculator") public class ArithmeticCalculatorImpl implements ArithmeticCalculator{}
2.2. Adding Scan Annotation and aspectj Support to 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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <!-- Configuring Packages for Automatic Scanning --> <context:component-scan base-package="com.hp.spring.aop.annotation"></context:component-scan> <!-- Configuration automatically matches aspectJ Annotated Java Class generates proxy objects --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
2.3. Write facet classes and define notifications
@Aspect //Annotation Definition Aspect @Component public class LoggingAspect { //Before advice @Before("execution(public int com.hp.spring.aop.annatation.ArithmeticCalculator.*(int, int))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); } //Before advice @After("execution(* com.hp.spring.aop.annatation.*.*(..))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } }
Because @before The same expression as @after So spring supports extracting expressions into a method. The extracted code is as follows:
package com.hp.spring.aop.annotation; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * You can use the @Order annotation to specify the priority of the section, the smaller the value, the higher the priority. */ @Order(2) @Aspect @Component public class LoggingAspect { /** * Define a method for declaring pointcut expressions. Generally, there is no need to add additional code to this method. * Use @Pointcut to declare pointcut expressions. * Other subsequent notifications use method names directly to refer to the current pointcut expression. */ @Pointcut("execution(public int com.hp.spring.aop.annotation.ArithmeticCalculator.*(..))") public void declareJointPointExpression(){} /** * Execute a piece of code before each method of each implementation class of the com.hp.spring.aop.annotation.ArithmeticCalculator interface starts */ @Before("declareJointPointExpression()") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); } /** * Code executed after method execution. Whether or not the method has an exception */ @After("declareJointPointExpression()") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } /** * The method normally ends the executed code * The return notification can access the return value of the method! */ @AfterReturning(value="declareJointPointExpression()", returning="result") public void afterReturning(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends with " + result); } /** * Code that executes when an exception occurs to the target method. * Exception objects can be accessed; and notification code can be specified to execute when a particular exception occurs */ @AfterThrowing(value="declareJointPointExpression()", throwing="e") public void afterThrowing(JoinPoint joinPoint, Exception e){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " occurs excetion:" + e); } /** * Circumferential notifications need to carry parameters of ProceedingJoinPoint type. * Circumferential notification is similar to the whole process of dynamic proxy: ProceedingJoinPoint type parameters can determine whether or not the target method is executed. * And the circular notification must have a return value, which is the return value of the target method. */ /* @Around("execution(public int com.hp.spring.aop.annotation.ArithmeticCalculator.*(..))") public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; String methodName = pjd.getSignature().getName(); try { //Before advice System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs())); //Target implementation approach result = pjd.proceed(); //Return notification System.out.println("The method " + methodName + " ends with " + result); } catch (Throwable e) { //Exception notification System.out.println("The method " + methodName + " occurs exception:" + e); throw new RuntimeException(e); } //Post notification System.out.println("The method " + methodName + " ends"); return result; } */ }
- Section two
package com.hp.spring.aop.annotation; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Order(1) @Aspect @Component public class VlidationAspect { @Before("com.hp.spring.aop.annotation.LoggingAspect.declareJointPointExpression()") public void validateArgs(JoinPoint joinPoint){ System.out.println("-->validate:" + Arrays.asList(joinPoint.getArgs())); } }
- Test class
package com.hp.spring.aop.annotation; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-aspectj.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator"); System.out.println(arithmeticCalculator.getClass().getName()); int result = arithmeticCalculator.add(1, 2); System.out.println("result:" + result); result = arithmeticCalculator.div(1000, 10); System.out.println("result:" + result); } }
-
package com.hp.spring.aop.annotation;
-
import org.springframework.context.ApplicationContext;
-
import org.springframework.context.support.ClassPathXmlApplicationContext;
-
public class Main {
-
public static void main(String[] args) {
-
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-aspectj.xml");
-
ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
-
System.out.println(arithmeticCalculator.getClass().getName());
-
int result = arithmeticCalculator.add(1, 2);
-
System.out.println("result:" + result);
-
result = arithmeticCalculator.div(1000, 10);
-
System.out.println("result:" + result);
-
}
-
}
Print out:
com.sun.proxy.$Proxy12
-->validate:[1, 2]
The method add begins with [1, 2]
The method add ends
The method add ends with 3
result:3
-->validate:[1000, 10]
The method div begins with [1000, 10]
The method div ends
The method div ends with 100
result:100
As you can see from the printed logs, like dynamic proxies, you can define various types of notifications.