The simplest HelloWorld example of aspectJ

Posted by Benjigga on Wed, 19 Feb 2020 08:27:02 +0100

The simplest HelloWorld example of aspectJ

This is the introduction of aspectJ. What's the difference between aspectJ and aop? aspectJ can also implement aop functions. aop generally refers to spring aop, which is a set of annotations such as @ Aspect/@Pointcut/@Before/@Around. The implementation principle is dynamic agent. aspectJ is more efficient in embedding notifications at the compiler level

As you can guess, aspectJ is similar to lombok in that the compiler helps you "write" the notification code (the logic of printing the log after interception, called "notification"). Although aspectJ is efficient, it needs a special compiler, so it is not as convenient as aop. aop is less efficient than aspectJ, but it can also be accepted. So I have never seen aspectJ used in my work for many years

Introduction and comparison of spring aop

Here is an excerpt from https://www.jianshu.com/p/872d3dbdc2ca

Spring AOP AspectJ
Implemented in pure Java Extended implementation using Java programming language
No separate compilation process is required AspectJ compiler (ajc) is required unless LTW is set
Run time weaving only Runtime weaving is not available. Support compile time, post compile and load time weaving
Weak function - only method level weaving is supported More powerful - can weave fields, methods, constructors, static initializers, final classes / methods, etc.
Can only be implemented on bean s managed by Spring containers Can be implemented on all domain objects
Only method execution pointcuts are supported Support all entry points
Delegates are created by target objects and facets are applied to these delegates Before executing the application (at runtime), all aspects are woven directly into the code
Much slower than AspectJ Better performance
Easy to learn and apply More complex than Spring AOP

HelloWorld of aspectj

Writing examples to experience aspectj is a good way to help understand things.

Here are the helloworld new steps of aspectJ. I built a project with web in springboot, because this project can use the web more easily.

Note during testing: sometimes you don't know if it's a cache. Running the test main method will find that the interception doesn't take effect. You need to recompile cmd+f9 to take effect

Steps:

  1. Build a project for testing
    In IDEA, click file - > New - > Project ->Spring initializer - > create a project including spring web all the way (the detailed steps are omitted, do not follow this operation strictly, you can use maven to build a project)
  2. Modify the compiler of IDEA
    Only modify the compiler of the current project without affecting the global: in IntelliJ idea - > preferences ->Build, execution, deployment - > compiler - > java compiler (this modification only affects the current project, so you can modify it safely!)

Change the compiler Javac to Ajc, and specify the location of aspectjtools.jar (see the following for the obtaining method)

  • How to get aspectjtools.jar

    • Download directly to the maven central warehouse page: search for aspectjtools and download the latest version. Version 1.9.5 Download , and then save it in your own directory, and reference the path

    • Or, introduce GAV into pom.xml of the project, download it in the local maven warehouse, find the path of the jar package, and reference it. The GAV introduced in the project to download the jar package can be deleted (it's ok if it's not deleted, but it's customary to delete the unneeded GAV)

      <!-- aspectjtools: Download what you need jar You can delete this after the package GAV -->
      <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjtools</artifactId>
          <version>1.9.5</version>
      </dependency>
      
  1. Introduce the required jar package, add the following GAV in pom.xml, which is a necessary jar

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

    If this jar package is missing, an exception not found by the class will be thrown at runtime

    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
    

    Add: it can be found that org.aspectj.lang.NoAspectBoundException is in the jar package of aspectj:aspectj:1.5.4 that we introduced.

    PS: actually, the jar of aspectjtools also has this class, so it's OK to choose one of the two gavs of aspectjtools and aspectjrt, or even keep one. However, we still keep aspectjrt to remove GAV of aspectjtools

  2. Create a new Aspect for intercepting; a new HelloWorld class for writing intercepted methods and main methods for testing

  • This aspect class is a file with an. AJ extension, such as LogAspectJ.aj. It needs to be compiled by the Acj compiler. The compiled file is also a clas file, such as LogAspectJ.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("Log before...");
        proceed();
        System.out.println("After log...");
    }
}

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!");
    }

    /**
     * Test method: run time discovery can be intercepted
     *
     * @param args
     */
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.sayHello();
    }
}
  1. Run HelloWorld's main method and find the print

    Before logging...
    Hello, AspectJ!
    After log...
    

    (if you don't print like this, check in two aspects. First, check file - > settings to see if it is the Adj compiler. IDEA seems to have a bug. If you change pom.xml a little, you will call back the original Java C compiler. Second, you may change the cache, such as sometimes changing System.out.println("before log..."); for example, changing the printed string to System.out.println("before log 222..."); It will be found that it doesn't work. In this case, use cmd+f9 to trigger compilation and then run.)

appendix

Decompile HelloWorld and LogAspectJ to get the following source code (decompile with 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("Log before...");
        ajc$around$com_wyf_test_aopaspectjspring_example01_LogAspectJ$1$8852f95proceed(ajc$aroundClosure);
        System.out.println("After log...");
    }

    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("Log before...");
        ajc$around$com_wyf_test_aopaspectjspring_example01_LogAspectJ$1$8852f95proceed(ajc$aroundClosure);
        System.out.println("After log...");
    }

    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;
    }
}

63 original articles published, 37 praised, 20000 visitors+
Private letter follow

Topics: Java Spring Maven IntelliJ IDEA