我想在kotlin中使用aspectj aop,这是我的代码:
我在annotation.lazy_list中的注释:
科特林:
package anotation
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class lazy_list
my aspectj aop class:
@Aspect
class ActiveListAop{
@Pointcut("execution(@annotation.lazy_list * *(..))")
fun profile() {
}
@Before("profile()")
fun testModeOnly(joinPoint: JoinPoint) {
println("123")
}
}
我的用法:
@lazy_list
fun all():List<T>{
return lazy_obj?.all() as List<T>
}
当我调用all()函数时,没有错误,但是不打印“123”,为什么?
答案 0 :(得分:5)
对于Kotlin中的注释过程,您必须启用并使用KAPT。如果没有通过Gradle或Maven插件添加,Kotlin代码中的注释处理将无法正常工作。
Kotlin插件支持Dagger或DBFlow等注释处理器。为了让他们使用Kotlin类,请使用kotlin-kapt插件。
另见:
答案 1 :(得分:3)
spring + kotlin + AOP工作不错,只需转到http://start.spring.io/并生成一个支持AOP的项目,你可以在这里看到一块 build.gradle ......
buildscript {
ext {
kotlinVersion = '1.2.30'
springBootVersion = '2.0.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
}
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'org.springframework.boot'
...
dependencies {
compile('org.springframework.boot:spring-boot-starter-aop')
...
}
插件 kotlin-spring 使所有类打开以允许AOP
然后,只需声明您的方面如下
@Aspect
@Component
class MyAspect {
...
重要:使用 @Aspect 和 @Component 注释
注释您的方面类一块蛋糕! :)
答案 2 :(得分:1)
检查@RobbyCornelissen的答案here。 我发现它有效,并感谢他。
答案 3 :(得分:1)
对于它的价值,我们需要在我们的android项目中进行AspectJ编织,但确实想迁移到Kotlin,所以我们不得不解决这个问题。因此,该线程中使用spring或maven的解决方案对我们不起作用。这是android gradle项目的解决方案,但是,这将中断增量编译,因此会减慢您的构建时间和/或最终破坏某些内容。直到我可以重新考虑我们的架构并逐步淘汰AspectJ为止,或者(希望如此)Android开始支持它。
kapt可以解决此问题的一些答案和对OP的注释,但是kapt允许您进行编译时注释处理,而不是进行编织。也就是说,注释处理器允许您基于注释生成代码,但不允许您将逻辑注入现有代码中。
在此博客的基础上,它向Android添加了AspectJ https://fernandocejas.com/2014/08/03/aspect-oriented-programming-in-android
您的kotlin类被编译为字节代码,而编译到另一个目录中。因此,此解决方案使用相同的过程来编织Java类,但在kotlin类文件上再次运行它
在您的App/build.gradle
顶部的:
buildscript {
ext.aspectjVersion = '1.9.1'
dependencies {
classpath "org.aspectj:aspectjtools:$aspectjVersion"
}
}
在App / build.gradle的底部添加:
android.applicationVariants.all { variant ->
// add the versionName & versionCode to the apk file name
variant.outputs.all { output ->
def newPath = outputFileName.replace(".apk", "-${variant.versionName}.${variant.versionCode}.apk")
outputFileName = new File(outputFileName, newPath)
def fullName = ""
output.name.tokenize('-').eachWithIndex { token, index ->
fullName = fullName + (index == 0 ? token : token.capitalize())
}
JavaCompile javaCompile = variant.javaCompiler
MessageHandler handler = new MessageHandler(true)
javaCompile.doLast {
String[] javaArgs = ["-showWeaveInfo",
"-1.8",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(
File.pathSeparator)]
String[] kotlinArgs = ["-showWeaveInfo",
"-1.8",
"-inpath", project.buildDir.path + "/tmp/kotlin-classes/" + fullName,
"-aspectpath", javaCompile.classpath.asPath,
"-d", project.buildDir.path + "/tmp/kotlin-classes/" + fullName,
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(
File.pathSeparator)]
new Main().run(javaArgs, handler)
new Main().run(kotlinArgs, handler)
def log = project.logger
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break
case IMessage.WARNING:
case IMessage.INFO:
log.info message.message, message.thrown
break
case IMessage.DEBUG:
log.debug message.message, message.thrown
break
}
}
}
}
答案 4 :(得分:1)
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "io.freefair.gradle:aspectj-plugin:5.2.1"
}
}
apply plugin: "io.freefair.aspectj.post-compile-weaving"
答案 5 :(得分:0)
所以我认为我有一个很好的(但罗word的)Android解决方案 。在撰写本文时,我正在使用Gradle 6.7,Android插件4.1.0和AspectJ工具1.9.6。
问题的要点是:
compileDebugJavaWithJavac
compileDebugKotlin
编译的compileDebugJavaWithJavac
取决于compileDebugKotlin
如果仔细研究这些要点,您会发现您无法在编译Kotlin时进行编织,因为此时Java类可能会丢失。如果这样做,您将收到诸如以下警告:
WARN:错误的类路径:C:\ Users \ user \ StudioProjects \ myapp \ app \ build \ intermediates \ javac \ debug \ classes
以及诸如
之类的错误错误:无法确定缺少类型myapp.Foo.Bar的修饰符
所以更好的方法是推迟编织,直到编译Java类为止。但是,由于您要在编译任务中修改文件 not ,您会丢失增量构建...此外,这种推迟的编织非常难于解决–请记住,所有编译任务都可能无法解决。实际计划运行!
真正的解决方案是将编织包裹在Transform
中,这将产生具有自己的输入和输出的Gradle任务。这意味着您将不会污染编译任务的文件,并且这些任务以及该任务将可以使用UP-TO-DATE。这需要很多代码,但这很明智!
首先,将其放入您的项目build.gradle.kts
:
buildscript {
dependencies {
classpath("org.aspectj:aspectjtools:1.9.6")
}
}
这是从构建脚本内部“编织”所需的。如果要在单独的过程中进行编织,这在Windows上是个好主意,则需要此jar的路径,可以通过将以下内容添加到应用程序build.gradle.kts
中来获得该路径:
val weaving: Configuration by configurations.creating
dependencies {
weaving("org.aspectj:aspectjtools:1.9.6")
}
最后,将AspectJ运行时放在类路径中(应用build.gradle.kts
,请注意,我只需要在调试版本中进行编织即可):
dependencies {
debugImplementation("org.aspectj:aspectjrt:1.9.6")
}
现在,这是我的设置。我有一个本地日志记录库:cats
,其中包含我要编织的方面。记录语句仅在我的项目中,而不在其他任何地方。另外,我只想在调试版本中运行它们。因此,这是将猫“编织”到应用程序(应用程序的build.gradle.kts
)中的转换:
class TransformCats : Transform() {
override fun getName(): String = TransformCats::class.simpleName!!
override fun getInputTypes() = setOf(QualifiedContent.DefaultContentType.CLASSES)
// only look for annotations in app classes
// transformation will consume these and put woven classes in the output dir
override fun getScopes() = mutableSetOf(QualifiedContent.Scope.PROJECT)
// ...but also have the rest on our class path
// these will not be touched by the transformation
override fun getReferencedScopes() = mutableSetOf(QualifiedContent.Scope.SUB_PROJECTS,
QualifiedContent.Scope.EXTERNAL_LIBRARIES)
override fun isIncremental() = false
// only run on debug builds
override fun applyToVariant(variant: VariantInfo) = variant.isDebuggable
override fun transform(invocation: TransformInvocation) {
if (!invocation.isIncremental) {
invocation.outputProvider.deleteAll()
}
val output = invocation.outputProvider.getContentLocation(name, outputTypes,
scopes, Format.DIRECTORY)
if (output.isDirectory) FileUtils.deleteDirectoryContents(output)
FileUtils.mkdirs(output)
val input = mutableListOf<File>()
val classPath = mutableListOf<File>()
val aspectPath = mutableListOf<File>()
invocation.inputs.forEach { source ->
source.directoryInputs.forEach { dir ->
input.add(dir.file)
classPath.add(dir.file)
}
source.jarInputs.forEach { jar ->
input.add(jar.file)
classPath.add(jar.file)
}
}
invocation.referencedInputs.forEach { source ->
source.directoryInputs.forEach { dir ->
classPath.add(dir.file)
}
source.jarInputs.forEach { jar ->
classPath.add(jar.file)
if (jar.name == ":cats") aspectPath.add(jar.file)
}
}
weave(classPath, aspectPath, input, output)
}
}
android.registerTransform(TransformCats())
这是上面提到的编织代码:
// ajc gets hold of some files such as R.jar, and on Windows it leads to errors such as:
// The process cannot access the file because it is being used by another process
// to avoid these, weave in a process, which `javaexec` will helpfully launch for us.
fun weave(classPath: Iterable<File>, aspectPath: Iterable<File>, input: Iterable<File>, output: File) {
val runInAProcess = OperatingSystem.current().isWindows
val bootClassPath = android.bootClasspath
println(if (runInAProcess) ":: weaving in a process..." else ":: weaving...")
println(":: boot class path: $bootClassPath")
println(":: class path: $classPath")
println(":: aspect path: $aspectPath")
println(":: input: $input")
println(":: output: $output")
val arguments = listOf("-showWeaveInfo",
"-1.8",
"-bootclasspath", bootClassPath.asArgument,
"-classpath", classPath.asArgument,
"-aspectpath", aspectPath.asArgument,
"-inpath", input.asArgument,
"-d", output.absolutePath)
if (runInAProcess) {
javaexec {
classpath = weaving
main = "org.aspectj.tools.ajc.Main"
args = arguments
}
} else {
val handler = MessageHandler(true)
Main().run(arguments.toTypedArray(), handler)
val log = project.logger
for (message in handler.getMessages(null, true)) {
when (message.kind) {
IMessage.DEBUG -> log.debug("DEBUG " + message.message, message.thrown)
IMessage.INFO -> log.info("INFO: " + message.message, message.thrown)
IMessage.WARNING -> log.warn("WARN: " + message.message, message.thrown)
IMessage.FAIL,
IMessage.ERROR,
IMessage.ABORT -> log.error("ERROR: " + message.message, message.thrown)
}
}
}
}
val Iterable<File>.asArgument get() = joinToString(File.pathSeparator)
(Windows部分使用weaving
配置;您可能不需要if
的任何一部分)
就这样!