微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将AspectJ java项目编入Spring boot项目

如何解决如何将AspectJ java项目编入Spring boot项目

我有一个名为 Test 的 Java 项目,其中包含所有方面。我想在另一个 Spring Boot 项目中使用这些方面。我正在研究一个 poc,将测试项目中的方面编织到一个 spring 启动应用程序中。这样做的有效方法是什么以及如何完成,请实施的人提出建议。

Java 项目代码使用方面进行测试

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Secured {
    public boolean isLocked() default false; 
}
@Aspect
public class SecuredMethodAspect {

    @pointcut("@annotation(secured)")
    public void callAt(Secured secured) {}

    @Around("callAt(secured)")
    public Object around(ProceedingJoinPoint pjp,Secured secured) throws Throwable {
        if (secured.isLocked()) {
             System.out.println(pjp.getSignature().toLongString() + " is locked");
            return pjp.proceed();
        } else {
            return pjp.proceed();
        }
    }
}
        <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>aspect</groupId>
        <artifactId>test</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>AspectJ-POC</name>
        <url>http://maven.apache.org</url>
    
        <properties>
            <maven.compiler.source>11</maven.compiler.source>
            <maven.compiler.target>11</maven.compiler.target>
            <java.version>11</java.version>
        </properties>
    
        <!-- nickwongdev aspectj maven plugin,this is for weaving of aspects -->
        <build>
            <plugins>
                <plugin>
                    <groupId>com.nickwongdev</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.12.6</version>
                    <configuration>
                        <source>11</source>
                        <target>11</target>
                        <complianceLevel>11</complianceLevel>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    
        <!-- aspectj runtime dependency -->
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.9.6</version>
            </dependency>
        </dependencies>
    
    </project>

解决方法

在克隆之前浏览您的项目时,我获得了一些快速的第一印象:

  • 您不应在编译时编织场景中同时使用 Lombok 和本机 AspectJ,请参阅 my answer here
  • 可能的解决方法是多阶段编译,即首先使用 Java + Lombok,然后使用 AspectJ 进行编译后编织,请参阅 my answer here。或者,使用 delombok 以首先生成将 Lombok 注释扩展为等效源代码的源代码,然后使用 AspectJ 编译生成的源。
  • 再看一遍,您的示例方面模块似乎没有使用任何 Lombok,因此您不需要该依赖项。但可能你的真实项目确实如此,因此我在上面发表了评论。
  • 当然,您可以按照您的建议使用编译时编织来编织您的切面。但是,在这种情况下,您需要正确配置 AspectJ Maven 插件,而您没有这样做。除了主应用程序之外,您需要在 Spring Boot 模块中告诉它在哪里可以找到方面库以及要编织哪些依赖项。你有没有读过插件文档,例如章节 Weaving classes in jarsUsing aspect librariesMulti-module use of AspectJ?我还在这里回答了大量相关问题。
  • 但实际上,将方面编织到 Spring 应用程序中的首选方法是使用加载时编织 (LTW),如Spring manual 中所述。这应该更容易配置,并且您不需要任何 AspectJ Maven 插件,并且在编译期间可能也不会出现任何 Lombok 问题。

从您的示例项目以及您的 AspectJ Maven 配置中没有任何 aspectLibrariesweaveDependencies 部分来看,您根本没有费心阅读任何文档,这让我想知道您在你试图让它发挥作用的一个月。

我想发表评论,解释您为什么要使用 CTW 而不是 LTW。我能想到的唯一原因是除了您的本机方面之外,您还希望在您的 Spring 应用程序中使用 Spring AOP 方面。但是如果你激活了原生的 AspectJ LTW,你就不能同时使用 Spring AOP。如果这不是问题,我推荐 LTW,因为它在 Spring 中有很好的记录和测试。 CTW 也没有问题,但在 POM 中更难理解和管理。


更新: 好的,我不想因为您使用 CTW 的原因而再等,而是决定向您展示一个 LTW 解决方案。我所做的是:

  • 从您的 Spring 项目中删除 AspectJ Maven 插件和 AspectJ 工具
  • 添加 src/main/resources/org/aspectj/aop.xml,将其配置为使用您的方面并定位您的基础包 + 子包
  • 修复切入点以也使用您的基础包 + 子包,因为在您的基础包中没有类。这是典型的初学者错误。您需要将 execution(* com.ak..*(..)).. 一起使用,而不仅仅是 com.ak.*

我使用的非必需化妆品是:

  • 从 Spring Boot 应用程序的 main 方法调用 context.getBean(TestController.class).mainRequest() 以自动生成某些方面输出,以避免必须使用 curl 或网络浏览器来调用本地 URL。
  • 将 Spring 应用程序用作通过 try-with-resources 自动关闭的应用程序,以便在创建所需的日志输出后关闭应用程序。
  • 更改方面以同时记录连接点,以便在日志中查看它实际拦截了哪些方法。否则所有日志行看起来都一样,这不是很有帮助。
  • 使用 try-finally 以确保继续执行原始方法后的日志消息在出现异常时也被记录。

差异看起来像这样(我希望你能阅读差异):

diff --git a/aspect-test-project/src/main/java/com/ak/aspect/MethodLogAspect.java b/aspect-test-project/src/main/java/com/ak/aspect/MethodLogAspect.java
--- a/aspect-test-project/src/main/java/com/ak/aspect/MethodLogAspect.java  (revision Staged)
+++ b/aspect-test-project/src/main/java/com/ak/aspect/MethodLogAspect.java  (date 1626233247623)
@@ -7,14 +7,14 @@
 @Aspect
 public class MethodLogAspect {
 
-   @Around("@annotation( MethodLog) && (execution(* com.ak.*(..)))")
+   @Around("@annotation(MethodLog) && execution(* com.ak..*(..))")
    public Object wrap(final ProceedingJoinPoint joinPoint) throws Throwable {
-       System.out.println("***Aspect invoked before calling method***");
-       
-       final Object obj = joinPoint.proceed();
-       
-       System.out.println("***Aspect invoked after calling method***");
-       
-       return obj;
+       System.out.println("[BEFORE] " + joinPoint);
+       try {
+           return joinPoint.proceed();
+       }
+       finally {
+       System.out.println("[AFTER]  " + joinPoint);
+       }
    }
 }
diff --git a/src/main/java/com/ak/ParentprojectSpringbootApplication.java b/src/main/java/com/ak/ParentprojectSpringbootApplication.java
--- a/src/main/java/com/ak/ParentprojectSpringbootApplication.java  (revision Staged)
+++ b/src/main/java/com/ak/ParentprojectSpringbootApplication.java  (date 1626233555873)
@@ -1,14 +1,17 @@
 package com.ak;
 
+import com.ak.controller.TestController;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ConfigurableApplicationContext;
 
 @SpringBootApplication(scanBasePackages = { "com.ak.*" })
-//@SpringBootApplication
 public class ParentprojectSpringbootApplication {
 
    public static void main(String[] args) {
-       SpringApplication.run(ParentprojectSpringbootApplication.class,args);
+       try (ConfigurableApplicationContext context = SpringApplication.run(ParentprojectSpringbootApplication.class,args)) {
+           context.getBean(TestController.class).mainRequest();
+       }
    }
 
 }
diff --git a/parentproject-springboot/pom.xml b/parentproject-springboot/pom.xml
--- a/parentproject-springboot/pom.xml  (revision Staged)
+++ b/parentproject-springboot/pom.xml  (date 1626232421474)
@@ -71,13 +71,6 @@
            <version>1.9.6</version>
        </dependency>
 
-       <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools -->
-       <dependency>
-           <groupId>org.aspectj</groupId>
-           <artifactId>aspectjtools</artifactId>
-           <version>1.9.6</version>
-       </dependency>
-
        <dependency>
            <groupId>com.ak.aspect</groupId>
            <artifactId>aspect-test-project</artifactId>
@@ -100,24 +93,6 @@
                </configuration>
            </plugin>
 
-           <plugin>
-               <groupId>com.nickwongdev</groupId>
-               <artifactId>aspectj-maven-plugin</artifactId>
-               <version>1.12.6</version>
-               <configuration>
-                   <source>11</source>
-                   <target>11</target>
-                   <complianceLevel>11</complianceLevel>
-               </configuration>
-               <executions>
-                   <execution>
-                       <goals>
-                           <goal>compile</goal>
-                           <goal>test-compile</goal>
-                       </goals>
-                   </execution>
-               </executions>
-           </plugin>
        </plugins>
    </build>
 

为方便起见,以下是完整的更改文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ak</groupId>
    <artifactId>parentproject-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>parentproject-springboot</name>
    <description>Test project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.ak.dependency</groupId>
            <artifactId>dependencyprojet</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!-- aspectj runtime dependency -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.6</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

        <dependency>
            <groupId>com.ak.aspect</groupId>
            <artifactId>aspect-test-project</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>

    <weaver options="-verbose -showWeaveInfo">
        <!-- only weave classes in our application-specific packages -->
        <include within="com.ak..*"/>
    </weaver>

    <aspects>
        <aspect name="com.ak.aspect.MethodLogAspect"/>
    </aspects>

</aspectj>
package com.ak.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MethodLogAspect {

    @Around("@annotation(MethodLog) && execution(* com.ak..*(..))")
    public Object wrap(final ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("[BEFORE] " + joinPoint);
        try {
            return joinPoint.proceed();
        }
        finally {
        System.out.println("[AFTER]  " + joinPoint);
        }
    }
}
package com.ak;

import com.ak.controller.TestController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(scanBasePackages = { "com.ak.*" })
public class ParentprojectSpringbootApplication {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext context = SpringApplication.run(ParentprojectSpringbootApplication.class,args)) {
            context.getBean(TestController.class).mainRequest();
        }
    }

}

现在您只需确保将 JVM 参数 -javaagent:/path/to/aspectjweaver-1.9.6.jar 添加到您的 Java 命令行以激活本机 AspectJ LTW。有关如何在 Spring 中以更复杂的方式配置 LTW 的更多详细信息,请阅读 Spring 手册的 Using AspectJ with Spring Applications 部分。

控制台日志应如下所示:

[AppClassLoader@3764951d] info AspectJ Weaver Version 1.9.6 built on Tuesday Jul 21,2020 at 13:30:08 PDT
[AppClassLoader@3764951d] info register classloader jdk.internal.loader.ClassLoaders$AppClassLoader@3764951d
[AppClassLoader@3764951d] info using configuration /C:/Users/alexa/Documents/java-src/SO_AJ_SpringCTWMultiModule_68040124/parentproject-springboot/target/classes/org/aspectj/aop.xml
[AppClassLoader@3764951d] info register aspect com.ak.aspect.MethodLogAspect
[AppClassLoader@3764951d] warning javax.* types are not being woven because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified
[RestartClassLoader@1f385e10] info AspectJ Weaver Version 1.9.6 built on Tuesday Jul 21,2020 at 13:30:08 PDT
[RestartClassLoader@1f385e10] info register classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@1f385e10
[RestartClassLoader@1f385e10] info using configuration /C:/Users/alexa/Documents/java-src/SO_AJ_SpringCTWMultiModule_68040124/parentproject-springboot/target/classes/org/aspectj/aop.xml
[RestartClassLoader@1f385e10] info register aspect com.ak.aspect.MethodLogAspect

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__,| / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.2)

(...)
[RestartClassLoader@1f385e10] weaveinfo Join point 'method-execution(com.ak.dependency.model.AccountInfo com.ak.service.TestService.incomingRequest())' in Type 'com.ak.service.TestService' (TestService.java:20) advised by around advice from 'com.ak.aspect.MethodLogAspect' (MethodLogAspect.java)
[RestartClassLoader@1f385e10] weaveinfo Join point 'method-execution(com.ak.dependency.model.AccountInfo com.ak.dependency.Route.accountInfo())' in Type 'com.ak.dependency.Route' (Route.java:12) advised by around advice from 'com.ak.aspect.MethodLogAspect' (MethodLogAspect.java)
[RestartClassLoader@1f385e10] weaveinfo Join point 'method-execution(com.ak.dependency.model.BalanceInfo com.ak.dependency.Pipeline.balanceInfo())' in Type 'com.ak.dependency.Pipeline' (Pipeline.java:11) advised by around advice from 'com.ak.aspect.MethodLogAspect' (MethodLogAspect.java)
(...)

Controller
[BEFORE] execution(AccountInfo com.ak.service.TestService.incomingRequest())
[BEFORE] execution(AccountInfo com.ak.dependency.Route.accountInfo())
[BEFORE] execution(BalanceInfo com.ak.dependency.Pipeline.balanceInfo())
[AFTER]  execution(BalanceInfo com.ak.dependency.Pipeline.balanceInfo())
[AFTER]  execution(AccountInfo com.ak.dependency.Route.accountInfo())
[AFTER]  execution(AccountInfo com.ak.service.TestService.incomingRequest())
(...)

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