首页 > 技术文章 > AspectJ简单Demo

youngyajun 2020-09-09 17:35 原文

1.AspectJ介绍

AspectJ是一个面向切面的框架,是Eclipse旗下的一个项目,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件,下面会介绍2种方式用例展示。

2.原生方式

2.1 下载Jar包

官网下载AspectJ的jar包;下载地址:https://www.eclipse.org/aspectj/downloads.php#stable_release

avatar

2.2 安装

进入AspectJ所在的jar包目录,CMD执行安装命令:

java -jar aspectj-1.9.6.jar

示例图如下:

avatar

安装完成:

avatar

2.3 环境配置

上一步安装完成AspectJ会提示要求配置环境变量;由于这里只是演示Demo,所以下面步骤采用直接带参数编译、运行即可;不怕麻烦的话自己也可以配置一下环境变量。

2.4 编写测试类、切面类

随便新建一个文件夹(我这里的路径是:“C:\Users\YYJ\Desktop\AspectJ_Test\src”),添加如下2个测试类,示图如下:

avatar

Boss.java

public class Boss {

    public static void main(String[] args) {
        Boss boss = new Boss();
        boss.meeting();
    }

    public void meeting() {
        System.out.println("The boss is in a meeting");
    }

}

BossAspect.java (AspectJ的特殊类)

public aspect BossAspect{
	//定义切点
    pointcut bossPoint() : execution(* meeting(..));
	
    //前置通知,对切点增强
	before() : bossPoint(){
		System.out.println("Prepare something for metting");
	}
	
}

2.5 利用ajc编译

由于偷懒没有配置AspectJ的环境变量,如果需要使用ajc命令,需要进入到AspectJ的安装目录的bin目录下执行

操作步骤:

CMD进入到AspectJ安装目录的bin目录

cd C:\YYJ\Software\Aspectj1.9\bin

执行编译(需要指定类所在的文件目录):

ajc C:\Users\YYJ\Desktop\AspectJ_Test\src\*.java  -injars C:\YYJ\Software\Aspectj1.9\lib\aspectjrt.jar

注释:

​ 1. C:\Users\YYJ\Desktop\AspectJ_Test\src\*.java 指定ajc需要编译哪些类,这里用的通配符

​ 2. -injars C:\YYJ\Software\Aspectj1.9\lib\aspectjrt.jar 没有配置环境变量,ajc编译时需要指定所需要依赖的jar,否则会报错:[error] classpath error: unable to find org.aspectj.lang.JoinPoint (check that aspectjrt.jar is in your classpath)

编译完成后如下如:

avatar

2.6 运行Main方法

由于main方法写在了Boss类中,直接运行boss类即可;步骤如下:

切换到Boss.class文件所在目录下

cd C:\Users\YYJ\Desktop\AspectJ_Test\src

带依赖执行java命令:

java -classpath ".;C:\YYJ\Software\Aspectj1.9\lib\aspectjrt.jar" Boss

注意:-classpath ".;C:\YYJ\Software\Aspectj1.9\lib\aspectjrt.jar" 红色处不能少,否则会报一些依赖错误

控制台输入如下:

avatar

可见Boss类中的meeting方法得到了增强

3.Maven插件方式

3.1 Maven工程项目结构图:

avatar

3.2 pom.xml文件关键依赖:

	<!-- aspectj核心依赖 -->
	<dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.11</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <Xlint>ignore</Xlint>
                    <complianceLevel>1.8</complianceLevel>
                    <encoding>UTF-8</encoding>
                    <verbose>true</verbose>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <!-- weave all classes -->
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
            	<groupId>org.apache.maven.plugins</groupId>
            	<artifactId>maven-compiler-plugin</artifactId>
            	<version>3.7.0</version>
            	<configuration>
            		<source>1.8</source>
            		<target>1.8</target>
            		<encoding>UTF-8</encoding>
            	</configuration>
            </plugin>
        </plugins>
    </build>

3.3 Boss类

/**
 * description: Boss类.
 */
public class Boss {

    public static void main(String[] args) {
        Boss boss = new Boss();
        boss.meeting();
    }

    public void meeting() {
        System.out.println("Boss开会!");
    }

}

3.4 Secretary类

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * description: Secretary类.
 */

@Aspect
public class Secretary {

    /**
     * description: 利用execution表达式定义切点
     */
    @Pointcut("execution(* com.demo.Boss.meeting(..))")
    public void pointCut(){
    }

    /**
     * description: 前置通知
     */
    @Before(value = "pointCut()")
    public void doSomething(JoinPoint joinPoint){
        System.out.println("通知员工时间、地点,告知大家Boss要开会");
    }

}

3.5 测试:

为了方便/偷懒,main()方法直接写在了Boss类中,启动Boss类中的main方法,查看控制台输出如下图:

avatar

利用IDEA自带的反编译,查看Boss.class、Secretary.class的反编译类信息

Boss.class

import org.aspectj.lang.JoinPoint;
import org.aspectj.runtime.reflect.Factory;

public class Boss {
    public Boss() {
    }

    public static void main(String[] args) {
        Boss boss = new Boss();
        boss.meeting();
    }

    public void meeting() {
        JoinPoint var1 = Factory.makeJP(ajc$tjp_0, this, this);
        Secretary.aspectOf().doSomething(var1);
        System.out.println("Boss开会!");
    }

    static {
        ajc$preClinit();
    }
}

Secretary.class

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.NoAspectBoundException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class Secretary {
    public Secretary() {
    }

    @Before("pointCut()")
    public void doSomething(JoinPoint joinPoint) {
        System.out.println("通知员工时间、地点,告知大家Boss要开会");
    }

    public static Secretary aspectOf() {
        if (ajc$perSingletonInstance == null) {
            throw new NoAspectBoundException("com.demo.Secretary", ajc$initFailureCause);
        } else {
            return ajc$perSingletonInstance;
        }
    }

    public static boolean hasAspect() {
        return ajc$perSingletonInstance != null;
    }

    static {
        try {
            ajc$postClinit();
        } catch (Throwable var1) {
            ajc$initFailureCause = var1;
        }

    }
}

由于Aspectj是静态织入,从反编译出来的class文件可以看出,字节码对应部分就已经被织入相应功能了。

推荐阅读