在新线程上运行时,ProceedingJoinPoint.proceed()在ClassCastException失败

时间:2015-06-26 01:20:01

标签: android aspectj

我设置和@Around方面在后台线程上运行方法,它看起来像这样

@Aspect
public class ThreadAspect {    
    @Around("call(@Background void *(..))")
    public void runInBackground(final ProceedingJoinPoint jp) throws Throwable {
        new Thread(new JPRunner(jp)).start();
    }

    private static class JPRunner implements Runnable {
        ...
        @Override
        public void run() {
            try {
                jp.proceed();
            } catch (Throwable e) {
                Log.e("TEST", "ThreadAspect", e);
            }
        }
    }
}

我将@Background注释应用于采用String的方法,但在ClassCastException

的行上失败并显示jp.proceed()
E/TEST    (20943): java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPoint

有趣的是,如果我没有使用某个帖子,那么这个电话就好了。如何让它在线程上运行?

如果重要,我会在this plugin使用android上的aspectj。

编辑:这是失败的代码

// Background.java
package com.github.larvyde.ex.aspect;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Background {}

// MainActivity.java
package com.github.larvyde.ex.aspect;

import android.os.Bundle;
import android.util.Log;

public class MainActivity extends android.support.v7.app.AppCompatActivity {
    @Override
    public void onCreate(Bundle saved) {
        super.onCreate(saved);

        Log.v("TEST", "calling runInBackground");
        runInBackground("run #1");
        Log.v("TEST", "calling runInBackground again");
        runInBackground("run #2");
    }

    @Background
    public void runInBackground(String str) {
        Log.v("TEST", str);
    }
}

// ThreadAspect.java
package com.github.larvyde.ex.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import android.util.Log;

@Aspect
public class ThreadAspect {
    @Around("call(@Background void *(..))")
    public void runInBackground(ProceedingJoinPoint jp) throws Throwable {
        new Thread(new JPRunner(jp)).start();
    }

    private static class JPRunner implements Runnable {
        private final ProceedingJoinPoint jp;

        public JPRunner(ProceedingJoinPoint jp) {
            this.jp = jp;
        }

        @Override
        public void run() {
            try {
                jp.proceed();
            } catch (Throwable e) {
                Log.e("TEST", "ThreadAspect", e);
            }
        }
    }
}

日志

$ adb logcat | egrep 'TEST|AndroidRuntime'
V/TEST    (21315): calling runInBackground
V/TEST    (21315): calling runInBackground again
E/TEST    (21315): ThreadAspect
E/TEST    (21315): java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPoint
E/TEST    (21315):  at com.github.larvyde.ex.aspect.MainActivity$AjcClosure1.run(MainActivity.java:1)
E/TEST    (21315):  at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149)
E/TEST    (21315):  at com.github.larvyde.ex.aspect.ThreadAspect$JPRunner.run(ThreadAspect.java:25)
E/TEST    (21315):  at java.lang.Thread.run(Thread.java:818)
E/TEST    (21315): ThreadAspect
E/TEST    (21315): java.lang.ClassCastException: java.lang.String cannot be cast to org.aspectj.lang.JoinPoint
E/TEST    (21315):  at com.github.larvyde.ex.aspect.MainActivity$AjcClosure3.run(MainActivity.java:1)
E/TEST    (21315):  at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149)
E/TEST    (21315):  at com.github.larvyde.ex.aspect.ThreadAspect$JPRunner.run(ThreadAspect.java:25)
E/TEST    (21315):  at java.lang.Thread.run(Thread.java:818)

1 个答案:

答案 0 :(得分:0)

对我来说这很好用,也许你的实际代码与你在这里发布的代码不同,或者你省略了重要的信息。看看我独立的例子:

标记注释:

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Background {}

驱动程序应用程序:

如您所见,一种方法由注释标记,另一种方法不标记。

package de.scrum_master.app;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class Application {
    static final DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    public static void foreground() {
        System.out.println(
            dateFormat.format(Calendar.getInstance().getTime()) +
            " - synchronous call"
        );
    }

    @Background
    public static void background() {
        System.out.println(
            dateFormat.format(Calendar.getInstance().getTime()) +
            " - asynchronous call"
        );
    }

    public static void main(String[] args) {
        foreground();
        background();
        foreground();
        background();
    }
}

没有AspectJ的控制台输出:

18:21:09 - synchronous call
18:21:09 - asynchronous call
18:21:09 - synchronous call
18:21:09 - asynchronous call

如您所见,这些方法按照调用它们的顺序记录,并且所有方法都具有相同的时间戳。

Aspect在自己的线程中异步运行标记的方法:

这几乎就是你的方面代码,但我插入了2秒的等待时间以展示@Background效果。

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class ThreadAspect {
    @Around("call(@de.scrum_master.app.Background void *(..))")
    public void runInBackground(final ProceedingJoinPoint jp) throws Throwable {
        new Thread(new JPRunner(jp)).start();
    }

    private static class JPRunner implements Runnable {
        ProceedingJoinPoint jp;
        JPRunner(ProceedingJoinPoint jp) { this.jp = jp; }

        @Override public void run() {
            try { Thread.sleep(2000); jp.proceed(); }
            catch (Throwable e) { e.printStackTrace(); }
        }
    }
}

使用AspectJ的控制台输出:

18:23:21 - synchronous call
18:23:21 - synchronous call
18:23:23 - asynchronous call
18:23:23 - asynchronous call

正如您在此处所见,两个异步调用(背景任务)在同步调用后2秒打印。