首页 > 解决方案 > 带有 Jcabi Maven 插件的 AspectJ 二进制编织不适用于 Kotlin 代码

问题描述

我正在尝试对将在方法执行之前和之后记录的函数运行一个小注释。

我所做的:(所有课程都在src/main/kotlin

注释类

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class LogMe

方面类

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


@Aspect
abstract class Aspect {

    @Around("@annotation(LogMe) && execution(* *(..))")
    fun logMe(joinPoint: ProceedingJoinPoint): Any {
        beforeExecution(joinPoint)
        afterExecution(joinPoint)

        return joinPoint.proceed()
    }

    private fun beforeExecution(joinPoint: JoinPoint) {
        println("[${joinPoint.signature.name} has started its execution]")
    }

    private fun afterExecution(joinPoint: JoinPoint) {
        println("[${joinPoint.signature.name} has ended its execution]")
    }
}

带有注解方法的 Foo 类

class Foo {

    @LogMe
    fun yourMethodAround() {
        println("Executing foo.yourMethodAround()")
    }
}

主文件

fun main(args: Array<String>) {
    val foo = Foo()
    foo.yourMethodAround()
}

我的 POM.xml(剪切版)

...
    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
            <version>1.3.40</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-reflect</artifactId>
            <version>1.3.40</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.4</version>
        </dependency>

        <!-- TEST -->
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test</artifactId>
            <version>1.3.40</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test-junit</artifactId>
            <version>1.3.40</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src/main/kotlin</sourceDirectory>
        <testSourceDirectory>src/test/kotlin</testSourceDirectory>
        <plugins>
            <plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <configuration>
                    <jvmTarget>1.8</jvmTarget>
                </configuration>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>1.3.40</version>
                <executions>
                    <execution>
                        <id>kapt</id>
                        <goals>
                            <goal>kapt</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <goals> <goal>compile</goal> </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <goals> <goal>test-compile</goal> </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.jcabi</groupId>
                <artifactId>jcabi-maven-plugin</artifactId>
                <version>0.14.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>ajc</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>MainKt</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
...

当我基本上运行这个 main 时,我得到的是它在我的 Foo 类方法中的 println:

Executing foo.yourMethodAround()

但是我没有得到我期望从 Aspect 类获得的执行前后原则。

你们之前有没有遇到过这个问题?这让我很苦恼,因为我无法理解这里发生了什么。

标签: mavenkotlinaopaspectjjcabi

解决方案


免责声明:

  • 我以前从未使用过 Jcabi 插件,通常我总是使用 AspectJ Maven 插件,也用于二进制编织。
  • 我以前从未使用过 Kotlin 语言,通常我使用 Java 或 Groovy。

现在有些事情在你的方面不好:

  • 不能是abstract,否则无法创建实例。
  • 对于void方法,它必须能够返回null,所以 Kotlin 返回类型应该是Any?
  • 您应该proceed()在日志消息之前和之后,否则日志输出将是错误的。
  • 假设你的类,尤其是注解类,不驻留在默认包中但有一个实际的包名,你需要在你的切入点中使用完全限定的类名,例如@annotation(de.scrum_master.app.LogMe)
  • 使用一个方面类名Aspect,即与注解同名@Aspect,只是在另一个包中,有点难看。你应该重命名它。

对我来说,这很好用:

package de.scrum_master.aspect

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

@Aspect
class LogAspect {
  @Around("@annotation(de.scrum_master.app.LogMe) && execution(* *(..))")
  fun logMe(joinPoint: ProceedingJoinPoint): Any? {
    beforeExecution(joinPoint)
    val result = joinPoint.proceed()
    afterExecution(joinPoint)
    return result
  }

  private fun beforeExecution(joinPoint: JoinPoint) {
    println("[${joinPoint.signature.name} has started its execution]")
  }

  private fun afterExecution(joinPoint: JoinPoint) {
    println("[${joinPoint.signature.name} has ended its execution]")
  }
}

此外,也许您还应该将 Jcabi 插件配置为语言级别的 Java 8。在这里没有它也可以工作,但根据您使用的语言功能,它可能会更好:

<configuration>
  <source>1.8</source>
  <target>1.8</target>
</configuration>

我的控制台mvn clean verify看起来像这样:

$ java -jar target/so-aj-kotlin-56890630-1.0-SNAPSHOT.jar
[yourMethodAround has started its execution]
Executing foo.yourMethodAround()
[yourMethodAround has ended its execution]

我的 IDE IntelliJ IDEA 并没有完全掌握二进制编织的东西,因为它不知道 Jcabi,只知道 AspectJ Maven。所以我只是将项目配置为将编译委托给 Maven:

将 IDEA 构建委托给 Maven

那么直接从IDEA运行应用程序时的日志输出是一样的。


推荐阅读