AspectJ 的使用

之前在自定义annotation的时候,发现注解可以在编译的时候 做 动作,就想到了能不能像 sping aop 的 aspectj 那样去切面呢?不过没有思路,就先找AspectJ来学习下.

官网
http://www.eclipse.org/aspectj/
文档
http://www.eclipse.org/aspectj/docs.php

准备:

下载aspect 的 包 http://www.eclipse.org/aspectj/downloads.php
我下载后解压为 有三个目录
bin —- aspect 的命令,如ajc等,
doc —- 文档 包括了example
lib —- 运行的时候,需要使用的jar包(spring也是依赖这些的)

介绍

网上有不少介绍 aspectj 的,不过很多写着和eclipse 集成,这里介绍 直接用 ajc编译的方法来 织入切面代码。

这章的代码来自下载的example

下面两个例子,一个是ltw,一个是tjp,均是入门的例子,
需要一个jar lib/aspectjrt.jar


├─examples
│  ├─ltw
│  │      HelloWorld.java
│  │      README
│  │      Tracing.aj
│  │
│  └─tjp
│          Demo.java
│          files.lst
│          GetInfo.java
│
└─lib
        aspectjrt.jar

先来看 ltw

两个文件
* HelloWorld.java

public class HelloWorld {
    public static void main (String[] args) {
        System.out.println("Hello World!");
    }
}
  • Tracing.aj
public aspect Tracing {

    private pointcut mainMethod () :
        execution(public static void main(String[]));

    before () : mainMethod() {
        System.out.println("> " + thisJoinPoint);
    }

    after () : mainMethod() {
        System.out.println("< " + thisJoinPoint);
    }
}
  • 用ajc来编译,ajc的命令和javac有像
$ ajc -d . -cp ./lib/aspectjrt.jar HelloWorld.java Tracing.aj
  • 编译后,生成两个class ,运行 HelloWorld.class:
$ java -cp ./lib/aspectjrt.jar;. HelloWorld
> execution(void HelloWorld.main(String[]))
Hello World!
< execution(void HelloWorld.main(String[]))

再看另外一个例子 ,examples 的tjp的项目

也是两个java文件,一个files.lst

  • files.lst 内容很简单,就写着 两个java文件
Demo.java
GetInfo.java
  • Demo.java
package tjp;

public class Demo {
    static Demo d;

    public static void main(String[] args){
        new Demo().go();
    }

    void go(){
        d = new Demo();
        d.foo(1,d);
        System.out.println(d.bar(new Integer(3)));
    }

    void foo(int i, Object o){
        System.out.println("Demo.foo(" + i + ", " + o + ")\n");
    }

    String bar (Integer j){
        System.out.println("Demo.bar(" + j + ")\n");
        return "Demo.bar(" + j  + ")";
    }
}
  • GetInfo.java
package tjp;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.CodeSignature;

aspect GetInfo {

   static final void println(String s){ System.out.println(s); }

   pointcut goCut(): cflow(this(Demo) && execution(void go()));

   pointcut demoExecs(): within(Demo) && execution(* *(..));

   Object around(): demoExecs() && !execution(* go()) && goCut() {
      println("Intercepted message: " +
          thisJoinPointStaticPart.getSignature().getName());
      println("in class: " +
          thisJoinPointStaticPart.getSignature().getDeclaringType().getName());
      printParameters(thisJoinPoint);
      println("Running original method: \n" );
      Object result = proceed();
      println("  result: " + result );
      return result;
   }

   static private void printParameters(JoinPoint jp) {
      println("Arguments: " );
      Object[] args = jp.getArgs();
      String[] names = ((CodeSignature)jp.getSignature()).getParameterNames();
      Class[] types = ((CodeSignature)jp.getSignature()).getParameterTypes();
      for (int i = 0; i < args.length; i++) {
         println("  "  + i + ". " + names[i] +
             " : " +            types[i].getName() +
             " = " +            args[i]);
      }
   }
}

编译(生成class):

...\examples>ajc -cp ../lib/aspectjrt.jar -argfil e tjp/files.lst -d .

运行:

...\examples>java -cp ../lib/aspectjrt.jar;. tjp/Demo

Intercepted message: foo
in class: tjp.Demo
Arguments:
  0. i : int = 1
  1. o : java.lang.Object = tjp.Demo@23fc625e
Running original method:

Demo.foo(1, tjp.Demo@23fc625e)

  result: null
Intercepted message: bar
in class: tjp.Demo
Arguments:
  0. j : java.lang.Integer = 3
Running original method:

Demo.bar(3)

  result: Demo.bar(3)
Demo.bar(3)

说明:

  • 看起来,spring的语法和aspectj的语法差不多,s但spring 只是用了语法,在切面技术,是用代理的方式来处理.,参考:https://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/.
  • 更多的功能和内容,会要看看aspectj的语法.
  • springaop用得不少,但aspecj这种要换编译器的,在什么场景会好使用呢?有点好奇
  • 呼应开头,annotation貌似没在aspectj基础上使用,看来技术线不一样
<think>嗯,用户想了解AspectJ使用方法。AspectJ是一个面向切面编程的框架,我需要先介绍它的基本概念,然后分步骤讲解使用方法。首先,可能需要提到AspectJ的安装和配置,然后是如何编写切面,定义切点和通知类型。还有,用户可能想知道如何与项目集成,比如在Maven或Gradle中的配置。另外,编译时织入和加载时织入的区别也很重要,应该分别说明。需要注意用户可能对AOP概念不熟悉,所以例子要简单明了。还要检查是否有遗漏的步骤,比如注解驱动和XML配置的区别,以及常见的应用场景,比如日志、事务管理等。确保步骤清晰,语法正确,用中文表达,避免技术术语过于复杂。</think>AspectJ 是一个面向切面编程(AOP)的扩展工具,可用于Java项目中实现横切关注点的模块化。以下是分步骤的使用方法说明: --- ### 一、环境配置 1. **安装AspectJ编译器** - 下载地址: https://www.eclipse.org/aspectj/downloads.php - 使用命令行安装: ```bash java -jar aspectj-x.x.x.jar ``` 2. **项目依赖** - Maven项目添加依赖: ```xml <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.7</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency> ``` --- ### 二、核心概念与语法 #### 1. **切面(Aspect)** - 用 `.aj` 文件或 `@Aspect` 注解定义: ```java @Aspect public class LoggingAspect { // 切点和通知在此定义 } ``` #### 2. **切点(Pointcut)** - 语法: `execution([修饰符] 返回类型 类路径.方法名(参数))` - 示例: ```java @Pointcut("execution(* com.example.service.*.*(..))") public void serviceMethods() {} ``` #### 3. **通知(Advice)** - **@Before**: 方法执行前触发 ```java @Before("serviceMethods()") public void beforeAdvice() { System.out.println("方法即将执行"); } ``` - **@After**: 方法执行后触发 - **@Around**: 包裹目标方法 ```java @Around("serviceMethods()") public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { System.out.println("方法执行前"); Object result = pjp.proceed(); System.out.println("方法执行后"); return result; } ``` --- ### 三、编译与织入 1. **编译时织入(CTW)** - 使用AspectJ编译器 `ajc` 编译代码: ```bash ajc -source 1.8 -target 1.8 -cp aspectjrt.jar YourAspect.aj YourClass.java ``` 2. **加载时织入(LTW)** - 在 `META-INF/aop.xml` 中配置切面: ```xml <aspectj> <aspects> <aspect name="com.example.LoggingAspect"/> </aspects> </aspectj> ``` - JVM启动参数添加: ```bash -javaagent:path/to/aspectjweaver.jar ``` --- ### 四、示例场景 #### 记录方法执行时间 ```java @Aspect public class PerformanceAspect { @Around("execution(* com.example.service.*.*(..))") public Object logTime(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); Object result = pjp.proceed(); long duration = System.currentTimeMillis() - start; System.out.println(pjp.getSignature() + " 耗时 " + duration + "ms"); return result; } } ``` --- ### 五、常见问题 1. **织入失败检查** - 确认依赖版本一致 - 检查切点表达式是否匹配目标方法 2. **与Spring集成** - 启用 `@EnableAspectJAutoProxy` - 使用 `<aop:aspectj-autoproxy/>` 配置 --- 通过以上步骤,可以快速在Java项目中应用AspectJ实现日志、事务、性能监控等横切逻辑的统一管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值