aspectJ最简单的HelloWorld例子

有目标就不怕路远。年轻人.无论你现在身在何方.重要的是你将要向何处去。只有明确的目标才能助你成功。没有目标的航船.任何方向的风对他来说都是逆风。因此,再遥远的旅程,只要有目标.就不怕路远。没有目标,哪来的劲头?一车尔尼雷夫斯基

导读:本篇文章讲解 aspectJ最简单的HelloWorld例子,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

aspectJ最简单的HelloWorld例子

这是aspectJ的入门。aspectJ和aop有什么区别? aspectJ也能够实现和aop功能,aop一般指spring的aop,就是指使用@Aspect/@Pointcut/@Before/@Around等注解的那一套,实现原理是动态代理。而aspectJ是更加高效的在编译器的层面上植入通知的

可以猜测,aspectJ 和 lombok 类似,都是编译器帮你 “写入” 了通知的代码(拦截后打印日志的逻辑,叫 “通知”)。虽然aspectJ高效,但是需要特别的编译器,所以没有aop来得方便,而aop相比aspectJ没那么高效但是也能接受,所以工作多年我从未见到在工作中使用aspectJ

简介和spring aop的对比

这里摘抄自 https://www.jianshu.com/p/872d3dbdc2ca

Spring AOP AspectJ
在纯 Java 中实现 使用 Java 编程语言的扩展实现
不需要单独的编译过程 除非设置 LTW,否则需要 AspectJ 编译器 (ajc)
只能使用运行时织入 运行时织入不可用。支持编译时、编译后和加载时织入
功能不强-仅支持方法级编织 更强大 – 可以编织字段、方法、构造函数、静态初始值设定项、最终类/方法等…。
只能在由 Spring 容器管理的 bean 上实现 可以在所有域对象上实现
仅支持方法执行切入点 支持所有切入点
代理是由目标对象创建的, 并且切面应用在这些代理上 在执行应用程序之前 (在运行时) 前, 各方面直接在代码中进行织入
比 AspectJ 慢多了 更好的性能
易于学习和应用 相对于 Spring AOP 来说更复杂

aspectj的HelloWorld

亲手写例子体验aspectj是很好的方法帮助理解的事情。

以下是 aspectJ 的 helloworld 新建步骤。我建的是springboot带web的项目,因为这个项目可以使用web比较方便。

测试的时候要注意:有时候不知道是不是缓存,运行测试main方法会发现拦截不生效,需要cmd+f9重新编译,才生效

步骤:

  1. 建测试用的project
    在 IDEA 里,点击 File->New->Project…->Spring Initialzer->一路进行创建包含spring web的project(详细步骤略,不用严格按照这操作,建一个project可以用maven即可)
  2. 修改 IDEA 的编译器
    仅修改当前project的编译器,不要影响到全局:在 IntelliJ IDEA->Preferences…->Build,Execution,Deployment->Compiler->Java Compiler(Windows是File->Settings->…)(这个修改仅影响当前project,放心修改!

将编译器Javac改成Ajc,并指定aspectjtools.jar的位置(获取方法见后

在这里插入图片描述

  • aspectjtools.jar的获取方法

    • 直接到maven中央仓库页面下载:搜索aspectjtools,并下载最新版即可。1.9.5版下载,然后保存在自己的某个目录,并引用这个路径

    • 或者,在project的pom.xml中引入GAV,下载在本地的maven仓库后找到这个jar包所在路径,引用它即可。project中为了下载这个jar包而引入的GAV可以删掉(不删也行,不过习惯把不需要的GAV删除)

      <!-- aspectjtools:下载好所需的jar包后可以删除这个GAV -->
      <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjtools</artifactId>
          <version>1.9.5</version>
      </dependency>
      
  1. 引入所需的jar包,pom.xml中增加如下GAV,这是必须的jar

    <!-- aspectj -->
    <dependency>
        <groupId>aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.5.4</version>
    </dependency>
    

    缺少这个jar包,会在运行时抛出类找不到的异常

    Exception in thread "main" java.lang.NoClassDefFoundError: org/aspectj/lang/NoAspectBoundException
    	at com.wyf.test.aopaspectjspring.example01.HelloWorld.main(HelloWorld.java:20)
    Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.NoAspectBoundException
    	at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    	... 1 more
    

    补充:可以发现 org.aspectj.lang.NoAspectBoundException 正是在我们引入的aspectj:aspectj:1.5.4的jar包中。

    PS:其实aspectjtools这个jar也是有这个类的,所以aspectjtools和aspectjrt两个GAV二选一也是可以的,或者连个都保留也是可以的。不过我们还是遵循留aspectjrt删除aspectjtools的GAV

  2. 新建Aspect,用于拦截;新建HelloWorld类,用于写被拦截的方法以及测试用的main方法

  • 这个aspect 类是一个.aj 扩展名的文件,如 LogAspectJ.aj,它需要Acj编译器来编译,编译后的文件也是clas文件,如 LogAspectJ.class (反编译这两个class发现还是跟普通的不一样)
package com.wyf.test.aopaspectjspring.example01;

/**
 *
 * @author Stone
 * @version V1.0.0
 * @date 2020/2/19
 */
public aspect LogAspectJ {
    void around(): call(void HelloWorld.sayHello()) {
        System.out.println("日志前...");
        proceed();
        System.out.println("日志后...");
    }
}

package com.wyf.test.aopaspectjspring.example01;

/**
 * @author Stone
 * @version V1.0.0
 * @date 2020/2/19
 */
public class HelloWorld {
    public void sayHello() {
        System.out.println("Hello, AspectJ!");
    }

    /**
     * 测试方法:运行时发现能够被拦截
     *
     * @param args
     */
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.sayHello();
    }
}
  1. 运行HelloWorld的main方法,发现打印

    日志前...
    Hello, AspectJ!
    日志后...
    

    (如果没有这么打印,2个方面排查。第一查看File->Settings查看下是不是Adj编译器,IDEA似乎有bug,只要稍微改一下pom.xml,就会打回原形用Javac编译器;第二可能是缓存,比如有时候改一下System.out.println("日志前..."); 的打印的字符串,比如改成 System.out.println("日志前222..."); 会发现不生效,这时使用cmd+f9触发一下编译再运行)

附录

反编译 HelloWorld 和 LogAspectJ,得到如下的源码(用IDEA反编译)’

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.wyf.test.aopaspectjspring.example01;

import org.aspectj.lang.NoAspectBoundException;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.runtime.internal.AroundClosure;

@Aspect
public class LogAspectJ {
    static {
        try {
            ajc$postClinit();
        } catch (Throwable var1) {
            ajc$initFailureCause = var1;
        }

    }

    public LogAspectJ() {
    }

    @Around(
            value = "call(void HelloWorld.sayHello())",
            argNames = "ajc$aroundClosure"
    )
    public void ajc$around$com_wyf_test_aopaspectjspring_example01_LogAspectJ$1$8852f95(AroundClosure ajc$aroundClosure) {
        System.out.println("日志前...");
        ajc$around$com_wyf_test_aopaspectjspring_example01_LogAspectJ$1$8852f95proceed(ajc$aroundClosure);
        System.out.println("日志后...");
    }

    public static LogAspectJ aspectOf() {
        if (ajc$perSingletonInstance == null) {
            throw new NoAspectBoundException("com_wyf_test_aopaspectjspring_example01_LogAspectJ", ajc$initFailureCause);
        } else {
            return ajc$perSingletonInstance;
        }
    }

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

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.wyf.test.aopaspectjspring.example01;

import org.aspectj.lang.NoAspectBoundException;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.runtime.internal.AroundClosure;

@Aspect
public class LogAspectJ {
    static {
        try {
            ajc$postClinit();
        } catch (Throwable var1) {
            ajc$initFailureCause = var1;
        }

    }

    public LogAspectJ() {
    }

    @Around(
            value = "call(void HelloWorld.sayHello())",
            argNames = "ajc$aroundClosure"
    )
    public void ajc$around$com_wyf_test_aopaspectjspring_example01_LogAspectJ$1$8852f95(AroundClosure ajc$aroundClosure) {
        System.out.println("日志前...");
        ajc$around$com_wyf_test_aopaspectjspring_example01_LogAspectJ$1$8852f95proceed(ajc$aroundClosure);
        System.out.println("日志后...");
    }

    public static LogAspectJ aspectOf() {
        if (ajc$perSingletonInstance == null) {
            throw new NoAspectBoundException("com_wyf_test_aopaspectjspring_example01_LogAspectJ", ajc$initFailureCause);
        } else {
            return ajc$perSingletonInstance;
        }
    }

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/135284.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!