java基于注解实现方法执行拦截_AspectJ 基于自定义的方法注解来拦截方法

本文介绍了一种使用AspectJ基于自定义注解@MonitorMethod进行方法拦截的方法,无需复杂的匹配规则,只需在目标方法上添加注解即可。通过创建@MonitorMethod注解、定义Aspect并配置拦截逻辑,实现了对被注解方法的执行时间监控。示例代码展示了如何创建注解、定义切面、编写业务方法以及测试运行。
摘要由CSDN通过智能技术生成

通常在使用 AspectJ 时都是基于识别方法的规则来进行方法拦截,例如切片里这样写

@Pointcut("execution(* *..StockService.getBaseInfo(..))")

它拦截到的是以 StockService 结尾的,方法名为 getBaseInfo,参数任意,返回值任意的方法。而我这里要说的一种方式是基于自定义注解来拦截方法的,此处的注解不是指 @Aspect, @Pointcut, 或 @Before 那一堆东西,而是指你可以自定义一个注解,如 @cc.unmi.testaspectj.MonitorMethod,被它所注解的方法即被拦截,像:

@cc.unmi.testaspectj.MonitorMethod

public void foo();

这可以给我们很大的自由度来快捷控制哪些方法需要被拦截,加个上面的注解 @MonitorMethod 即可,而不像从前那般要想像用什么规则去匹配某个方法,用 || 连接起来,同时还要防止影响到别的不期望被拦截的方法。

需要的代码并不多,四步,创建自定义注解类 MonitorMethod, 需被拦截的方法加上 @MonitorMethod,方面类,测试类。

1. MonitorMethod.java

package cc.unmi.testaspectj;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface MonitorMethod {

String value() default "";

}

1

2

3

4

5

6

7

8

9

10

11

12

packagecc.unmi.testaspectj;

importjava.lang.annotation.ElementType;

importjava.lang.annotation.Retention;

importjava.lang.annotation.RetentionPolicy;

importjava.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public@interfaceMonitorMethod{

Stringvalue()default"";

}

2. MethodExecutionTime.java

package cc.unmi.testaspectj;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.util.StopWatch;

/**

* @author Unmi

*/

@Aspect

public class MethodExecutionTime {

@Around("execution(* *.*(..)) && @annotation(cc.unmi.testaspectj.MonitorMethod)")

public Object profile(ProceedingJoinPoint  pjp) throws Throwable {

StopWatch sw = new StopWatch(getClass().getSimpleName());

try {

sw.start(pjp.getSignature().toShortString());

return pjp.proceed();

} finally {

sw.stop();

System.out.println(sw.prettyPrint());

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

packagecc.unmi.testaspectj;

importorg.aspectj.lang.ProceedingJoinPoint;

importorg.aspectj.lang.annotation.Around;

importorg.aspectj.lang.annotation.Aspect;

importorg.springframework.util.StopWatch;

/**

* @author Unmi

*/

@Aspect

publicclassMethodExecutionTime{

@Around("execution(* *.*(..)) && @annotation(cc.unmi.testaspectj.MonitorMethod)")

publicObjectprofile(ProceedingJoinPoint pjp)throwsThrowable{

StopWatchsw=newStopWatch(getClass().getSimpleName());

try{

sw.start(pjp.getSignature().toShortString());

returnpjp.proceed();

}finally{

sw.stop();

System.out.println(sw.prettyPrint());

}

}

}

上面是简单的写法,也可以把 @Pointcut 和 @Around 分开来,如先声明

@Pointcut("execution(* *.*(..)) && @annotation(cc.unmi.testaspectj.MonitorMethod)")

public void methodsToBeProfiled(){}

把用

@Around("methodsToBeProfiled()")

注解到 profile() 方法

3. StockService.java

package cc.unmi.testaspectj;

/**

* @author Unmi

*/

public class StockService {

@MonitorMethod

public String getBaseInfo(String ticker){

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

return "";

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

packagecc.unmi.testaspectj;

/**

* @author Unmi

*/

publicclassStockService{

@MonitorMethod

publicStringgetBaseInfo(Stringticker){

try{

Thread.sleep(500);

}catch(InterruptedExceptione){

e.printStackTrace();

}

return"";

}

}

4. AspectJTestClient.java

package cc.unmi.testaspectj;

/**

* @author Unmi

*/

public class AspectJTestClient {

public static void main(String[] args) {

new StockService().getBaseInfo("MSFT");

//new FundService().getBaseInfo("BBBIX");

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

packagecc.unmi.testaspectj;

/**

* @author Unmi

*/

publicclassAspectJTestClient{

publicstaticvoidmain(String[]args){

newStockService().getBaseInfo("MSFT");

//new FundService().getBaseInfo("BBBIX");

}

}

这样,因为 StockService 的 getBaseInfo 加上了 @MonitorMethod 注解,所以可被拦截到,假如有个类 FundService 的 getBaseInfo 方法未加上 @MonitorMethod 注解,将不被拦截到。

执行结果如下:

StopWatch 'MethodExecutionTime': running time (millis) = 500

-----------------------------------------

ms     %     Task name

-----------------------------------------

00500  100%  StockService.getBaseInfo(..)

1

2

3

4

5

StopWatch'MethodExecutionTime':runningtime(millis)=500

-----------------------------------------

ms    %    Taskname

-----------------------------------------

00500 100% StockService.getBaseInfo(..)

如果你用 AJDT 的话,可以在 MethodExecutionTime.java 和 StockService.java 编辑器里看到箭头指示拦截到了什么方法,以及 Cross References View 中看到关联关系。

补充(2015-01-21)

因为写此文时是用的 AJDT 插件做的,所以是自动织入的,如果是命令行的话就要用到  ajc 或 aspectjtools.jar 来编译,可以直接起动 aspecttools.jar AspectJ Browser 来处理。这里以 Mac 平台命令行为例,假如项目目录结构如下:

├── lib

│   ├── aspectjrt.jar

│   ├── aspectjtools.jar

│   ├── aspectjweaver.jar

│   └── spring-core-2.5.6.jar

└── src

└── cc

└── unmi

└── testaspectj

├── AspectJTestClient.java

├── MethodExecutionTime.java

├── MonitorMethod.java

└── StockService.java

1

2

3

4

5

6

7

8

9

10

11

12

13

├──lib

│  ├──aspectjrt.jar

│  ├──aspectjtools.jar

│  ├──aspectjweaver.jar

│  └──spring-core-2.5.6.jar

└──src

└──cc

└──unmi

└──testaspectj

├──AspectJTestClient.java

├──MethodExecutionTime.java

├──MonitorMethod.java

└──StockService.java

编译:

$ javac -classpath lib/aspectjtools.jar:lib/aspectjrt.jar:lib/spring-core-2.5.6.jar org.aspectj.tools.ajc.Main -d bin -source 1.7  src/cc/unmi/testaspectj/*

执行:

$java -classpath bin:lib/aspectjrt:lib/spring-core-2.5.6.jar:lib/aspectjweaver.jar cc.unmi.testaspectj.AspectJTestClient

这样就输出上面的结果:

StopWatch 'MethodExecutionTime': running time (millis) = 505

-----------------------------------------

ms     %     Task name

-----------------------------------------

00505  100%  StockService.getBaseInfo(..)

由于 Spring 2.0 开始支持 AspectJ,因此你可以把上面的方法应用到 Spring 中去。可参考:

参考:http://www.captaindebug.com/2011/09/using-springs-aspectj-support-and.html

好像在通过 Spring 使用 AspectJ 时私有方法不被拦截到,而单独用 AspectJ 不会有这样的局限。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值