网上比较常见的AOP实现都是基于spring框架,通过spring Aop实现面向切面编程。但是在很多非spring框架的项目中,如果想要实现AOP,就可以选用AspectJ去实现。
AspectJ 简介
AspectJ是一个面向切面的框架,简单的说就是它是AOP的一种实现框架。
AspectJ基于Java进行了扩展,所以可以完全兼容java,因此使用AspectJ有两种方式:
- 完全使用AspectJ的语言。这语言一点也不难,和Java几乎一样,也能在AspectJ中调用Java的任何类库。AspectJ只是多了一些关键词罢了。(基于aspect文件)
- 使用纯Java语言开发,然后使用AspectJ注解,简称@AspectJ。(基于java注解)
注:由于AspectJ对Java进行了扩展,用java原生的编辑器编译是行不通,必须使用AspectJ特有的编辑器进行编译。本文仅介绍基于java注解的方式实现AOP
AspectJ Jar包介绍
重点jar包有三个:
- aspectjrt.jar:提供运行时的一些注解,静态方法等;
- aspectjtools.jar:赫赫有名的ajc编辑器,可以在编译器java文件获取class文件或者aspect文件定义的切面织入到业务代码中;(一般会封装进IDE插件或者自动化插件中)
- aspectjweaver.jar:提供一个java agent,用于在类加载期间织入切面;
aspectJ的三种织入方式:
- 编译时织入:利用ajc编辑器代替java编辑器,直接将 java/aspect 文件编译成class文件并且织入切面。
- 编译后织入:利用ajc编辑器向java编辑器编译生产的class文件中织入切面。
- 加载时织入:不适用ajc编辑器,利用aspectjweaver.jar工具,使用java agent代理在类加载期间将切面织入。
基于java注解的AspectJ
一般情况我们大都会选择原生的Java环境进行开发,所有这里主要讲解基于Java注解的AspectJ。
新建maven项目并添加依赖如下:
<!-- Aspectj 依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
注意指定JDK的版本为1.8
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
添加maven自动化构建插件:aspectj-maven-plugin
;该插件会绑定到编译期,采用编译后织入的方式,在maven-compiler-plugin插件执行之后运行。
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.11</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<complianceLevel>1.8</complianceLevel>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
创建业务类App类
package org.dylan.demo.aspectj;
public class App {
public static void main(String[] args) {
System.out.println(new App().say());
}
public String say() {
return "World";
}
}
创建切面类AspectDemo
package org.dylan.demo.aspectj;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect //标识该类是一个切面类
public class AspectDemo {
@Pointcut("execution(* org.dylan.demo.aspectj.App.say())") // 定义切入点
private void pointcut() {
}
@Before("pointcut()") // 定义通知(增强方法的代码)
public void before() {
System.out.println("Hello");
}
}
编译运行 App.main():

使用自定义注解标记切入点
一般实际的开发场景下,切入点会比较混杂,如果通过路径的方式列举会很复杂,而通过自定义注解的方式则可以简洁不少,下面我们以记录日志为例:
创建自定义注解@Log
package org.dylan.demo.aspectj;
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 Log {
String operation() default "日志注解注入测试";
}
创建切面类 LogAspect
package org.dylan.demo.aspectj;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class LogAspect {
@Pointcut("execution(@org.dylan.demo.aspectj.Log * *..*.*(..)) && @annotation(logAnno)")
public void pointCut(Log logAnno) {
}
@Before("pointCut(logAnno)")
public void before(Log logAnno) {
System.out.println("运行前 执行增强代码" + logAnno.operation());
}
@After("pointCut(logAnno)")
public void after(Log logAnno) {
System.out.println("运行后 执行增强代码" + logAnno.operation());
}
}
新增测试类 LogDemo
package org.dylan.demo.aspectj;
public class LogDemo {
public static void main(String[] args) {
new LogDemo().test();
}
@Log
public void test() {
System.out.println("Hello World!");
}
}
编译运行 LogDemo.main()

COMMENTS | NOTHING