使用 AspectJ 注释提供重写方法执行后的逻辑

Using AspectJ annotations to provide logic following execution of an overridden method

目标:使用 AspectJ 在执行特定方法后调用静态方法。

为了问题的方便,我们调用静态方法System.out.println和方法onConfigurationChanged.

约束条件:

  1. onConfigurationChanged方法在class中声明、实现和调用我无法控制(无法编织)*。
  2. 因为 onConfigurationChanged 在基础 class 中有一个实现,子 classes 可能会也可能不会覆盖它(但是 System.out.println 仍然应该在onConfigurationChanged 在两种情况下都执行)。
  3. 使用注释语法,因为我的开发环境似乎不支持对本机方面语法的支持。

* 注意:这是在构建 Android 应用程序的上下文中,因此所讨论的基础 class 实际上是 android.app.Activity。很明显,编译时编织是不可能的。我已经研究过加载时织入,但我有点不确定如何在这种情况下完成它,甚至不确定我是否想要,因为它是如此关键的代码路径。

我目前面临的主要问题确实是 subclass 没有覆盖方法的情况。

我试过的:

上面的方法适用于 subclass 覆盖 onConfigurationChanged 方法的情况。

不幸的是,上面没有将方面提供的onConfigurationChanged实现添加到不覆盖onConfigurationChanged的子class中。它确实指定 subclass 实现了 OnConfigurationChangedListener 接口,但由于该方法是在其父 class 中实现的,编译器不会报错。 (如果我稍微调整接口方法的签名,使其不再匹配,我看到它确实被添加了,但这不是期望的结果。)

非常感谢任何帮助,谢谢。

出于技术原因,您必须使用本机语法,因为 declare parents@DeclareParents@DeclareMixin 更强大。

Eclipse 和 IntelliJ IDEA 都支持 AspectJ 本机语法。虽然我不知道 NetBeans。你用哪个IDE?您在 Eclipse 中找到的对高级 AspectJ 语法功能的最佳支持,IDEA 有一些缺点。但是抛开语法高亮、代码完成和重构等不错的功能不谈,您可以在任何编辑器中编写方面。

关于您的问题,我想强调我不是 Android 开发人员,所以我只是重新创建了您使用这两个虚拟 Android API 的基本功能 classes 以便使我的方面可测试:

把这些放到一个普通的Java项目中(或者使用原来的AndroidAPI):

package android.app;

import android.content.res.Configuration;

public class Activity {
    public void onConfigurationChanged (Configuration newConfig) {
        System.out.println("onConfigurationChanged - default implementation");
    }
}
package android.content.res;

public class Configuration {}

现在我们在 IDE 中创建另一个项目,这次是 AspectJ 项目。它应该引用上面的小虚拟 Android API 仿真。

在 AspectJ 项目中,我们创建了两个 Activity subclasses 用于演示,一个覆盖 onConfigurationChanged 和一个不覆盖它:

package com.jkhong.app;

import android.app.Activity;
import android.content.res.Configuration;

public class OverridingActivity extends Activity {
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        System.out.println("onConfigurationChanged - subclass override");
    }
}
package com.jkhong.app;

import android.app.Activity;

public class NonOverridingActivity extends Activity {}

通过一个小的驱动程序应用程序,我们可以展示会发生什么:

package com.jkhong.app;

import android.app.Activity;
import android.content.res.Configuration;

public class Application {
    public static void main(String[] args) {
        Configuration newConfig = new Configuration();
        System.out.println("Activity");
        new Activity().onConfigurationChanged(newConfig);
        System.out.println("\nOverridingActivity");
        new OverridingActivity().onConfigurationChanged(newConfig);
        System.out.println("\nNonOverridingActivity");
        new NonOverridingActivity().onConfigurationChanged(newConfig);
    }
}

控制台日志如下所示:

Activity
onConfigurationChanged - default implementation

OverridingActivity
onConfigurationChanged - default implementation
onConfigurationChanged - subclass override

NonOverridingActivity
onConfigurationChanged - default implementation

如您所见,OverridingActivity 在执行任何其他操作之前调用其 super 方法。我建议您始终这样做。对于 NonOverridingActivity,仅执行基础 class 的默认实现,正如预期的那样。

下面是解决您问题的方面:

package com.jkhong.aspect;

import android.app.Activity;
import android.content.res.Configuration;

public aspect ConfigurationChangeInterceptor {
    public static class DefaultChangeListener extends Activity {
        @Override
        public void onConfigurationChanged (Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            doDefaultOnConfigurationChanged();
        }
    }

    declare parents : Activity+ && !Activity extends DefaultChangeListener;

    private static void doDefaultOnConfigurationChanged() {
        System.out.println("onConfigurationChanged - aspect override");
    }
}

请注意方面如何使用 Activity+ && !Activity 指定 "all Activity subclasses but not Activity itself" 以避免编译器错误,因为 Activity 无法扩展自身并且无论如何都不会暴露给编织器。

控制台日志现在看起来像这样:

Activity
onConfigurationChanged - default implementation

OverridingActivity
onConfigurationChanged - default implementation
onConfigurationChanged - aspect override
onConfigurationChanged - subclass override

NonOverridingActivity
onConfigurationChanged - default implementation
onConfigurationChanged - aspect override

所以现在你拥有了你想要的。它为 NonOverridingActivityOverridingActivity.

触发的日志输出