正如我在评论中所说:在几乎所有情况下,使用适当的设计模式比开始依赖诸如 dynamic proxies、reflection 或 AOP 之类的东西来解决此类问题更可取。
话虽如此,问题是在编译时通过元编程修改 Kotlin 函数是否可能,答案是“是”。为了演示,下面是一个使用AspectJ的完整示例。
项目结构
我建立了一个基于Maven 的小型项目,其结构如下:
.
├── pom.xml
└── src
└── main
└── kotlin
├── Aop.kt
└── Main.kt
我将重现以下部分中所有文件的内容。
应用代码
实际的应用程序代码在名为 Main.kt 的文件中,并且——除了我将你的函数重命名为符合 Kotlin naming rules 的事实——它与提供的代码相同你的问题。 getNumber() 方法旨在返回 3。
fun main(args: Array<String>) {
println(getNumber())
}
fun getNumber(): Int {
return 3
}
AOP 代码
AOP相关的代码在Aop.kt,非常简单。它有一个@Around 通知,其切入点与getNumber() 函数的执行相匹配。该通知将拦截对getNumber() 方法的调用并返回42(而不是3)。
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
@Aspect
class Aop {
@Around("execution(* MainKt.getNumber(..))")
fun getRealNumber(joinPoint: ProceedingJoinPoint): Any {
return 42
}
}
(注意为Main.kt文件生成的类的名称是MainKt。)
POM 文件
POM 文件将所有内容放在一起。我正在使用 4 个插件:
这是完整的 POM 文件:
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>x.y.z</groupId>
<artifactId>kotlin-aop</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<kotlin.version>1.2.61</kotlin.version>
<aspectj.version>1.9.1</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
</execution>
<execution>
<id>compile</id>
<goals>
<goal>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>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
构建和执行
要构建,与任何 Maven 项目一样,您只需运行:
mvn clean package
这将在target/kotlin-aop-1.0-SNAPSHOT.jar 位置构建一个胖 JAR。然后可以使用java 命令执行此 JAR:
java -jar target/kotlin-aop-1.0-SNAPSHOT.jar
执行然后给我们以下结果,证明一切都按预期工作:
42
(应用程序是在撰写本文时使用最新的 Oracle Java 8 JDK — 1.8.0_181 构建和执行的)
结论
如上例所示,重新定义 Kotlin 函数当然是可能的,但是——重申我的原点——在几乎所有情况下,都有更优雅的解决方案可以满足您的需求。