AspectJ使用实例
2020-07-18 04:23
971 查看
一、在 Spring 中启用 AspectJ 注解支持
-
1要在 Spring 应用中使用 AspectJ 注解, 必须在 classpath 下包含 AspectJ 类库: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
maven 引入<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将 aop Schema 添加到 根元素中.
-
3要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素
<!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
4当 Spring IOC 容器侦测到 Bean 配置文件中的 元素时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理.
二、AspectJ 支持 5 种类型的通知注解:
- @Before: 前置通知, 在方法执行之前执行
- @After: 后置通知, 在方法执行之后执行
- @AfterRunning: 返回通知, 在方法返回结果之后执行
- @AfterThrowing: 异常通知, 在方法抛出异常之后
- @Around: 环绕通知, 围绕着方法执行
2.1、使用之前的 计算器接口和实现类 ArithmeticCalculator.java , ArithmeticCalculatorImpl.java
@Component("arithmeticCalculator") public class ArithmeticCalculatorImpl implements ArithmeticCalculator{}
2.2、在xml中增加扫描注解和aspectj的支持
<?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"> <!-- 配置自动扫描的包 --> <context:component-scan base-package="com.hp.spring.aop.annotation"></context:component-scan> <!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
2.3、编写切面类,定义各种通知
@Aspect //注解定义切面 @Component public class LoggingAspect { //前置通知 @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)); } //前置通知 @After("execution(* com.hp.spring.aop.annatation.*.*(..))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } }
由于@before 和@after的表达式都一样,所以spring支持对表达式进行抽取成一个方法,抽取后的代码如下:
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; /** * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高 */ @Order(2) @Aspect @Component public class LoggingAspect { /** * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. * 使用 @Pointcut 来声明切入点表达式. * 后面的其他通知直接使用方法名来引用当前的切入点表达式. */ @Pointcut("execution(public int com.hp.spring.aop.annotation.ArithmeticCalculator.*(..))") public void declareJointPointExpression(){} /** * 在 com.hp.spring.aop.annotation.ArithmeticCalculator 接口的每一个实现类的每一个方法开始之前执行一段代码 */ @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)); } /** * 在方法执行之后执行的代码. 无论该方法是否出现异常 */ @After("declareJointPointExpression()") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } /** * 在方法法正常结束受执行的代码 * 返回通知是可以访问到方法的返回值的! */ @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); } /** * 在目标方法出现异常时会执行的代码. * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码 */ @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); } /** * 环绕通知需要携带 ProceedingJoinPoint 类型的参数. * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法. * 且环绕通知必须有返回值, 返回值即为目标方法的返回值 */ /* @Around("execution(public int com.hp.spring.aop.annotation.ArithmeticCalculator.*(..))") public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; String methodName = pjd.getSignature().getName(); try { //前置通知 System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs())); //执行目标方法 result = pjd.proceed(); //返回通知 System.out.println("The method " + methodName + " ends with " + result); } catch (Throwable e) { //异常通知 System.out.println("The method " + methodName + " occurs exception:" + e); throw new RuntimeException(e); } //后置通知 System.out.println("The method " + methodName + " ends"); return result; } */ }
- 切面二
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())); } }
- 测试类
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);
-
}
-
}
打印出:
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
打印的日志中,可以看出,跟动态代理一样,可以定义各类通知。
转载于:https://my.oschina.net/milletes/blog/3085078
相关文章推荐
- spring 4.0 AOP (使用AspectJ的注解方式 的aop实现)简单实例
- spring 4.0 AOP (使用AspectJ的注解方式 的aop实现)简单实例
- spring 4.0 AOP (使用AspectJ的注解方式 的aop实现)简单实例
- AspectJ使用实例
- Java使用AES加密和解密的实例详解
- 使用WEBLOGIC7.0配置ProxyServer实例
- Photoshop入门与进阶实例:1.3 工具箱的使用
- 在Windows下使用GCJ+SWT的实例
- 实例讲解.NET中资源文件的创建与使用
- Photoshop入门与进阶实例:1.5 图层蒙版的使用
- Vector ArrayList Hashtable的使用实例
- CBuilder中使用管道技术实例
- JDK 1.5 特性使用实例1--Generics
- SAFEARRAY使用实例
- AspectJ使用经验
- Photoshop入门与进阶实例:1.6 路径的使用
- Rational Purify 使用及分析实例
- 使用反射动态创建类的实例
- VB中使用ASP对象实例
- 如何在BCB中配置和使用GDI+技术?(附动画实例)