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

时间:2016-03-01 18:31:03

标签: java aspectj

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

为了解决这个问题,让我们调用静态方法System.out.println和方法onConfigurationChanged

约束:

  1. 在我无法控制的类中声明,实现和调用onConfigurationChanged方法(无法编织)*。
  2. 由于onConfigurationChanged在基类中有一个实现,子类可能会也可能不会覆盖它(但在System.out.println执行onConfigurationChanged之后仍应调用android.app.Activity。“ / LI>
  3. 使用注释语法,因为我的开发环境似乎不支持对原生方面语法的支持。
  4. *注意:这是在构建Android应用程序的上下文中,因此所讨论的基类实际上是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的子类。它确实指定子类实现<!-- saved from url=(0014)about:internet --> <!DOCTYPE HTML> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=8; IE=7; IE=EDGE" charset="utf-8"> <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/base/jquery-ui.css"></link> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <script> function displayData() { $.get('http://www.w3schools.com/json/myTutorials.txt', function(responseText) { alert(responseText); }); } </script> </head> <body> <div id="menu"> <button type="button" id="btnDisplay" onclick="displayData()">Go</button> </div> </body> </html> 接口,但由于该方法是在其父类中实现的,因此编译器不会抱怨。 (如果我略微调整接口方法的签名,以便它不再匹配,我看到它确实被添加了,但这不是理想的结果。)

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

1 个答案:

答案 0 :(得分:1)

出于技术原因,您必须使用原生语法,因为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

所以现在你有你想要的东西。它为NonOverridingActivity以及OverridingActivity触发的日志输出。