【问题标题】:Create custom java annotation in order to modify method创建自定义 java 注释以修改方法
【发布时间】:2017-11-28 22:01:13
【问题描述】:

我想创建一个注解,以使方法像 Spring 中的 @Async 一样异步,但适用于 Android。我检查了 java 的注解处理器,但它不允许修改现有类(我们只能创建新类)我不想使用 androidannotation 库,因为我也想学习如何创建自己的注解

我看到lombok允许修改类(添加getter和setter),我们可以添加自定义注释(https://binkley.blogspot.fr/2014/12/writing-your-own-lombok-annotation.html

但我无法修改此示例以创建异步任务并注入方法的代码。

感谢您的帮助

@AsyncTask
void doSomething(int a){
    Log.d("here");
}

-->

void doSomething(int a){
    new android.os.AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground( Void... voids ) {
            Log.d("here");
            return null;
        }
    }.execute();
}

【问题讨论】:

  • 修改类是危险的,需要为每个 jvm 维护。如何创建生成的类或使用代理?

标签: java android annotations


【解决方案1】:

首先,我们定义注解:

@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface AsyncTask {
}

然后我们使用cglib@AsyncTask 方法创建异步逻辑:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

public class AsyncTaskHandler {
  @SuppressWarnings("unchecked")
  public static <T> T handle(T origin) {
    // collect async methods
    List<Method> asyncMethods = Arrays.stream(origin.getClass().getMethods())
        .filter(m -> m.getAnnotation(AsyncTask.class) != null)
        .collect(Collectors.toList());
    // if no async method, return itself
    if (asyncMethods.isEmpty()) {
      return origin;
    }
    return (T) Enhancer.create(origin.getClass(), (MethodInterceptor) (obj, method, args, proxy) -> {
      // if asyn, wrapped in your async code, here I simply create a new thread
      if (asyncMethods.contains(method)) {
        // your async logic
        new Thread(() -> {
          try {
            proxy.invoke(origin, args);
          } catch (Throwable e) {
            e.printStackTrace();
          }
        }).start();
        return null;
      }
      return proxy.invoke(origin, args);
    });
  }
}

让我们测试一下我们的代码。

public class SomeObject {

  public static void main(String[] args) {
    SomeObject so = SomeObject.create();
    so.syncDo("1");
    so.asyncDo("2");
    so.syncDo("3");
    so.asyncDo("4");
  }

  public static SomeObject create() {
    return AsyncTaskHandler.handle(new SomeObject());
  }

  protected SomeObject() {}

  @AsyncTask
  public void asyncDo(String who) {
    System.out.println(who + "\tThread: " + Thread.currentThread());
  }

  public void syncDo(String who) {
    System.out.println(who + "\tThread: " + Thread.currentThread());
  }
}

输出是:

1   Thread: Thread[main,5,main]
3   Thread: Thread[main,5,main]
2   Thread: Thread[Thread-0,5,main]
5   Thread: Thread[Thread-1,5,main]

【讨论】:

  • 您好非常感谢您的回答,但出于性能原因,我希望在编译期间而不是在运行时修改代码的注释。这就是我对使用这种机制的 lombok 感兴趣的原因。
  • @kazouz Lombok 修改 AST 以生成新的字节码。很难维护。您将在注释处理中创建新的类文件,而不是更改现有代码。
猜你喜欢
  • 2021-01-08
  • 2017-07-19
  • 2019-02-08
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多