Как заставить аспект переплетать kotlin код каждый раз с помощью gradle - PullRequest
0 голосов
/ 18 июня 2020

Я изучаю АОП и использую gradle + aspectJ для создания своего кода. Итак, я сделал, как говорится в какой-то демонстрации, добавил аспектJtools в начало build.gradle.

dependencies {
    ...
    classpath 'org.aspectj:aspectjtools:1.9.5'
}

И в app / build.gradle добавьте задачу в код плетения:

variants.all { variant ->
    JavaCompile javaCompile
    if (variant.hasProperty('javaCompileProvider')) {
        //android gradle 3.3.0 +
        javaCompile = variant.javaCompileProvider.get()
    } else {
        javaCompile = variant.javaCompile
    }
    def buildType = variant.buildType.name

    javaCompile.doLast {

        MessageHandler handler = new MessageHandler(true)

        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)
        ]
        new Main().run(javaArgs, handler)

        String[] kotlinArgs = [
                "-showWeaveInfo",
                "-1.8",
                "-inpath", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
                "-aspectpath", javaCompile.classpath.asPath,
                "-d", project.buildDir.path + "/tmp/kotlin-classes/" + buildType,
                "-classpath", javaCompile.classpath.asPath,
                "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)
        ]
        new Main().run(kotlinArgs, handler)

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

Затем я добавьте мой аспект, например:

@Aspect
public class AspectInCommon extends BaseAspect {

    @Pointcut("execution(* com.example.cheng.test.MainActivityKt.on**(..))")
    public void kotlinMainOn() {
    }

    @After("kotlinMainOn()")
    public void hookKotlinMain(JoinPoint joinPoint) throws Throwable {
        log(joinPoint.getSignature().toLongString());
    }

    ...
}

И мой MainActivity выглядит так:

    class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
    }
}

Таким образом, я действительно вплел аспект в свой код. И вот некоторые результаты: enter image description here Сначала он работает нормально, пока я снова не нажму кнопку «Отладка внизу», после чего весь вывод больше не запускается. Затем, после нескольких тестов, я обнаружил, что после чистой сборки он переплетается только в том случае, если один из моих файлов находится в kotlin. Поэтому я пытаюсь изменить mainActivity и файл аспекта на java или kotlin. И вот результаты теста:

MainActivity language       Aspect language        Weave results
Java                        Java                   Weave every time
Java                        Kotlin                 Weave after clean build *
Kotlin                      Java                   Weave after clean build
Kotlin                      Kotlin                 Weave after clean build

*: я поместил файл аспекта в подмодуль, и он вылетел во второй сборке после чистой сборки. Сообщение об ошибке:

java.lang.NoSuchMethodError: No static method aspectOf()

Интересно, как сделать аспектное переплетение кода kotlin каждый раз, а не только один раз после чистой сборки, потому что большая часть кода моего реального проекта основана на kotlin. Идеально не использовать просто плагин. Большое спасибо.

1 Ответ

1 голос
/ 18 июня 2020

Я не использую ни Gradle (скорее Maven), ни Kotlin, но мой опыт работы с несколькими языками JVM или несколькими шагами компиляции показывает, что имеет смысл выполнять каждый шаг компиляции в отдельном модуле.

  1. Таким образом, у вас может быть один модуль класса приложения Java + Kotlin, компилирующий его с помощью обычных компиляторов Java / Kotlin.
  2. Тогда у вас есть модуль аспекта, скомпилированный с помощью компилятора AspectJ.
  3. Наконец, есть модуль, выполняющий двоичное переплетение с AspectJ, используя первый модуль на пути inpath, а второй - на пути аспекта.

Это делает сборку более простой и стабильной. Другие преимущества заключаются в том, что у вас есть оригинальный, нетканый модуль приложения и модуль с улучшенным аспектом. В зависимости от ситуации вы можете использовать первое или второе в своем приложении, например, если вы переплетаете аспекты отладки или трассировки, которые не всегда следует использовать. И последнее, но не менее важное: отдельный модуль аспектов делает библиотеку аспектов потенциально пригодной для повторного использования.

...