Spring+AspectJ+ 简单方式来拦截方法,监测性能
还是在很久以前,作过一篇 用 AOP 来记录每个方法的执行时间(Spring 或直接 AspectJ), 其中例示了三种方法来拦截方法,用以监测方法调用时间它们分别是:
1. Spring 2.0 用 AspectJ 实现 AOP
2. Spring 通用的方法拦截
3. 直接用 AspectJ 实现
在这里再次使用 <aop:aspect-autoproxy/> 再 @Aspect 注解的方式来写个新的例子。原理与前面基本一致,只是在类里用 @Aspect, @Pointcut, @Before, @After, @Around, @AfterReturning, @AfterThrowing 来写拦截类。
局限仍然是必须通过 Spring 的 BeanFactory 获得的实例才能被拦截到,除非是在 Eclipse 里安装 AJDT 或是使用 Maven-AspectJ Plugin 来编译工程。
好,我们来看完整的例子,下面列出所有的项目文件,这是一个 Maven 的项目,所以从 pom.xml 开始。
1. pom.xml
如果这是一个 Eclipse 中的 AJDT 项目,只要 spring-aspects 一个依赖即可。
2. applicatinContext.xml
spring 从 2.0 起就可支持 aop 标签。<aop:aspectj-autoproxy/> 的作用其实是声明了一个 AnnotationAwareAspectJAutoProxyCreator 自动代理创建器实例,它会根据 MethodExecutionTime 中声明的 @Pointcut 注解中的条件去代理符合条件的实例,这些被代理的实例必须在配置到 spring 中去。
3. MethodExecutionTime.java
这个类完全是 AspectJ 的用法范畴了。这个类必须用 @Aspect 标注,@Pointcut 注明拦截条件,支持逻辑操作,例如这里用 || 操作符配置了拦截多个方法。有关 AspectJ 的 Pointcut 语法请参考:http://www.eclipse.org/aspectj/doc/released/progguide/language.html。
如果你的 Eclipse 安装了 AJDT 插件,并且是一个 AspectJ 项目,那么我们现在的这个例子可以完全不需要 spring,即可以不需要 pom.xml 文件,可以不用 applicationContext.xml,也不用在乎你的 StockService/FundService 如何得来的。
并且你在 Eclipse 中可以看到如下景象:


4. StockService.java 和 FundService
它们都有个 public String getBaseInfo(String ticker) 方法。
5. AspectJTestClient.java
这是一个测试类,验证了必须通过 Spring BeanFactory 得到的实例,调用方法时才能被拦截 。执行上面代码的输出如下:
可以看出通过 Spring BeanFactory 获得的实例被拦截了,直接初始化的实例不受影响。
但如果你的 Eclipse 安装了 AJDT 插件,并且你的项目还是一个 AspectJ 项目,那么不管你是怎么获得的 StockService/FundService 实例,在调用它们的方法时都会被 MethodExecutionTime 拦截到。并且此时在 pom.xml 中只需要保留 spring-aspects 一个依赖即可。 永久链接 https://yanbin.blog/spring-aspectj-intercept-method/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
1. Spring 2.0 用 AspectJ 实现 AOP
2. Spring 通用的方法拦截
3. 直接用 AspectJ 实现
在这里再次使用 <aop:aspect-autoproxy/> 再 @Aspect 注解的方式来写个新的例子。原理与前面基本一致,只是在类里用 @Aspect, @Pointcut, @Before, @After, @Around, @AfterReturning, @AfterThrowing 来写拦截类。
局限仍然是必须通过 Spring 的 BeanFactory 获得的实例才能被拦截到,除非是在 Eclipse 里安装 AJDT 或是使用 Maven-AspectJ Plugin 来编译工程。
好,我们来看完整的例子,下面列出所有的项目文件,这是一个 Maven 的项目,所以从 pom.xml 开始。
1. pom.xml
1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3 <modelVersion>4.0.0</modelVersion>
4 <groupId>cc.unmi</groupId>
5 <artifactId>TestSpring</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7 <name>TestSpring</name>
8 <dependencies>
9 <dependency>
10 <groupId>org.springframework</groupId>
11 <artifactId>spring-aspects</artifactId>
12 <version>3.1.2.RELEASE</version>
13 </dependency>
14 <dependency>
15 <groupId>aspectj</groupId>
16 <artifactId>aspectjrt</artifactId>
17 <version>1.5.4</version>
18 </dependency>
19 <dependency>
20 <groupId>aspectj</groupId>
21 <artifactId>aspectjweaver</artifactId>
22 <version>1.5.4</version>
23 </dependency>
24 <dependency>
25 <groupId>cglib</groupId>
26 <artifactId>cglib</artifactId>
27 <version>2.2</version>
28 </dependency>
29 </dependencies>
30</project>如果这是一个 Eclipse 中的 AJDT 项目,只要 spring-aspects 一个依赖即可。
2. applicatinContext.xml
1<?xml version="1.0" encoding="UTF-8"?>
2
3<beans xmlns="http://www.springframework.org/schema/beans"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xmlns:aop="http://www.springframework.org/schema/aop"
6 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
7 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
8
9 <bean class="cc.unmi.testspringaspectj.MethodExecutionTime"/>
10 <aop:aspectj-autoproxy/>
11
12 <bean id="stockService" class="cc.unmi.testspringaspectj.StockService"/>
13 <bean id="fundService" class="cc.unmi.testspringaspectj.FundService"/>
14
15</beans>spring 从 2.0 起就可支持 aop 标签。<aop:aspectj-autoproxy/> 的作用其实是声明了一个 AnnotationAwareAspectJAutoProxyCreator 自动代理创建器实例,它会根据 MethodExecutionTime 中声明的 @Pointcut 注解中的条件去代理符合条件的实例,这些被代理的实例必须在配置到 spring 中去。
3. MethodExecutionTime.java
1package cc.unmi.testspringaspectj;
2
3import org.aspectj.lang.ProceedingJoinPoint;
4import org.aspectj.lang.annotation.Around;
5import org.aspectj.lang.annotation.Aspect;
6import org.aspectj.lang.annotation.Pointcut;
7import org.springframework.util.StopWatch;
8
9/**
10 * @author Unmi
11 */
12
13@Aspect
14public class MethodExecutionTime {
15
16 @Pointcut("execution(* *..StockService.getBaseInfo(..))" +
17 " || execution(* *..FundService.getBaseInfo(..))" +
18 ")")
19 public void methodsToBeProfiled(){}
20
21 @Around("methodsToBeProfiled()")
22 public Object profile(ProceedingJoinPoint pjp) throws Throwable {
23 StopWatch sw = new StopWatch(getClass().getSimpleName());
24 try {
25 sw.start(pjp.getSignature().toShortString());
26 return pjp.proceed();
27 } finally {
28 sw.stop();
29 System.out.println(sw.prettyPrint());
30 }
31 }
32}这个类完全是 AspectJ 的用法范畴了。这个类必须用 @Aspect 标注,@Pointcut 注明拦截条件,支持逻辑操作,例如这里用 || 操作符配置了拦截多个方法。有关 AspectJ 的 Pointcut 语法请参考:http://www.eclipse.org/aspectj/doc/released/progguide/language.html。
如果你的 Eclipse 安装了 AJDT 插件,并且是一个 AspectJ 项目,那么我们现在的这个例子可以完全不需要 spring,即可以不需要 pom.xml 文件,可以不用 applicationContext.xml,也不用在乎你的 StockService/FundService 如何得来的。
并且你在 Eclipse 中可以看到如下景象:


4. StockService.java 和 FundService
它们都有个 public String getBaseInfo(String ticker) 方法。
5. AspectJTestClient.java
1package cc.unmi.testspringaspectj;
2
3import org.springframework.beans.factory.BeanFactory;
4import org.springframework.context.support.ClassPathXmlApplicationContext;
5
6/**
7 * @author Unmi
8 */
9public class AspectJTestClient {
10
11 /**
12 * @param args
13 */
14 public static void main(String[] args) {
15 BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
16
17 StockService stockService = factory.getBean(StockService.class);
18 FundService fundService = factory.getBean(FundService.class);
19
20 stockService.getBaseInfo("IBM");
21 fundService.getBaseInfo("BBBIX");
22
23 //cannot be intercepted
24 new StockService().getBaseInfo("MSFT");
25 }
26}这是一个测试类,验证了必须通过 Spring BeanFactory 得到的实例,调用方法时才能被拦截 。执行上面代码的输出如下:
1StopWatch 'MethodExecutionTime': running time (millis) = 512
2-----------------------------------------
3ms % Task name
4-----------------------------------------
500512 100% StockService.getBaseInfo(..)
6
7StopWatch 'MethodExecutionTime': running time (millis) = 316
8-----------------------------------------
9ms % Task name
10-----------------------------------------
1100316 100% FundService.getBaseInfo(..)可以看出通过 Spring BeanFactory 获得的实例被拦截了,直接初始化的实例不受影响。
但如果你的 Eclipse 安装了 AJDT 插件,并且你的项目还是一个 AspectJ 项目,那么不管你是怎么获得的 StockService/FundService 实例,在调用它们的方法时都会被 MethodExecutionTime 拦截到。并且此时在 pom.xml 中只需要保留 spring-aspects 一个依赖即可。 永久链接 https://yanbin.blog/spring-aspectj-intercept-method/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。