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



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

为了解决这个问题,我们把静态方法称为System.out.println,方法称为onConfigurationChanged

约束条件:

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

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

我目前面临的主要问题是子类不覆盖该方法的情况。

我尝试过:

  • onConfigurationChanged签名指定的执行切入点,定义了@After建议,调用System.out.println

    @After("execution(void com.jkhong..*.onConfigurationChanged()) "
        + "&& !within(DefaultOnConfigurationChangedAspect)")
    public void onConfigurationChangedExecution() {
        doDefaultOnConfigurationChanged();
    }
    private static void doDefaultOnConfigurationChanged() {
        System.out.println("Default onConfigurationChanged (mixed in)");
    }
    

上述方法适用于子类覆盖onConfigurationChanged方法的情况。

  • @DeclareMixin以子类为目标,返回调用 System.out.println 的匿名类实现。返回的接口具有与基类中onConfigurationChanged完全相同的签名的单个方法。

    public interface OnConfigurationChangedListener {
        void onConfigurationChanged();
    }
    @DeclareMixin("com.jkhong..*.*Activity")
    public static OnConfigurationChangedListener createDefaultListener() {
        return new OnConfigurationChangedListener() {
            @Override
            public void onConfigurationChanged() {
                doDefaultOnConfigurationChanged();
            }
        };
    }
    

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

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

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

Eclipse 和 IntelliJ IDEA 都支持 AspectJ 原生语法。不过,我不知道 NetBeans。您使用哪个 IDE?在Eclipse中找到对高级AspectJ语法功能的最佳支持,IDEA有一些缺点。但是忽略语法突出显示、代码完成和重构等不错的功能,您可以在任何编辑器中编写一个方面。

至于你的问题,我想强调一下,我不是Android开发人员,所以我只是重新创建了你在这两个虚拟类中使用的基本Android API功能,以使我的方面可测试:

将这些放入一个普通的Java项目中(或使用原始的Android API):

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子类进行演示,一个覆盖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,仅按预期执行基类的默认实现。

现在这是解决您问题的方面:

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来指定"所有子类Activity但不是Activity自身",以避免编译器错误,因为Activity无法扩展自身,并且无论如何都不会暴露给编织者。

控制台日志现在如下所示:

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

所以现在你得到了你想要的。它为 NonOverridingActivityOverridingActivity 触发的日志输出。

最新更新