使用 AspectJ 注释提供重写方法执行后的逻辑
Using AspectJ annotations to provide logic following execution of an overridden method
目标:使用 AspectJ 在执行特定方法后调用静态方法。
为了问题的方便,我们调用静态方法System.out.println
和方法onConfigurationChanged
.
约束条件:
onConfigurationChanged
方法在class中声明、实现和调用我无法控制(无法编织)*。
- 因为
onConfigurationChanged
在基础 class 中有一个实现,子 classes 可能会也可能不会覆盖它(但是 System.out.println
仍然应该在onConfigurationChanged
在两种情况下都执行)。
- 使用注释语法,因为我的开发环境似乎不支持对本机方面语法的支持。
* 注意:这是在构建 Android 应用程序的上下文中,因此所讨论的基础 class 实际上是 android.app.Activity
。很明显,编译时编织是不可能的。我已经研究过加载时织入,但我有点不确定如何在这种情况下完成它,甚至不确定我是否想要,因为它是如此关键的代码路径。
我目前面临的主要问题确实是 subclass 没有覆盖方法的情况。
我试过的:
使用 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)");
}
上面的方法适用于 subclass 覆盖 onConfigurationChanged
方法的情况。
@DeclareMixin
以子 class 为目标,返回调用 System.out.println
的匿名 class 实现。返回的接口有一个方法,其签名与基础 class.
中的 onConfigurationChanged
完全相同
public interface OnConfigurationChangedListener {
void onConfigurationChanged();
}
@DeclareMixin("com.jkhong..*.*Activity")
public static OnConfigurationChangedListener createDefaultListener() {
return new OnConfigurationChangedListener() {
@Override
public void onConfigurationChanged() {
doDefaultOnConfigurationChanged();
}
};
}
不幸的是,上面没有将方面提供的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
所以现在你拥有了你想要的。它为 NonOverridingActivity
和 OverridingActivity
.
触发的日志输出
目标:使用 AspectJ 在执行特定方法后调用静态方法。
为了问题的方便,我们调用静态方法System.out.println
和方法onConfigurationChanged
.
约束条件:
onConfigurationChanged
方法在class中声明、实现和调用我无法控制(无法编织)*。- 因为
onConfigurationChanged
在基础 class 中有一个实现,子 classes 可能会也可能不会覆盖它(但是System.out.println
仍然应该在onConfigurationChanged
在两种情况下都执行)。 - 使用注释语法,因为我的开发环境似乎不支持对本机方面语法的支持。
* 注意:这是在构建 Android 应用程序的上下文中,因此所讨论的基础 class 实际上是 android.app.Activity
。很明显,编译时编织是不可能的。我已经研究过加载时织入,但我有点不确定如何在这种情况下完成它,甚至不确定我是否想要,因为它是如此关键的代码路径。
我目前面临的主要问题确实是 subclass 没有覆盖方法的情况。
我试过的:
使用
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)"); }
上面的方法适用于 subclass 覆盖 onConfigurationChanged
方法的情况。
中的@DeclareMixin
以子 class 为目标,返回调用System.out.println
的匿名 class 实现。返回的接口有一个方法,其签名与基础 class.onConfigurationChanged
完全相同public interface OnConfigurationChangedListener { void onConfigurationChanged(); } @DeclareMixin("com.jkhong..*.*Activity") public static OnConfigurationChangedListener createDefaultListener() { return new OnConfigurationChangedListener() { @Override public void onConfigurationChanged() { doDefaultOnConfigurationChanged(); } }; }
不幸的是,上面没有将方面提供的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
所以现在你拥有了你想要的。它为 NonOverridingActivity
和 OverridingActivity
.