从任务访问异步方法参数或方法的注释
Accessing async method parameters or method's annotations from task
我有下面的 类(简化)来使用 Java 和 Spring 工具箱实现异步方法调用。我需要添加一些需要在异步方法调用之前和之后执行的逻辑。
可调用。如果可以访问数据,我可以把我需要的逻辑放在这里。
public class ContextAwareCallable<T> implements Callable<T> {
private Callable<T> task;
private MyContext context;
public ContextAwareCallable(Callable<T> task, MyContext context) {
this.task = task;
this.context = context;
}
@Override
public T call() throws Exception {
return task.call();
}
}
这里是executor,调用task的地方。
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
private static final long serialVersionUID = 1L;
@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable<T>(task, myContext));
}
这是配置器。初始化执行器。据我所知,我可以在这里放一个 TaskDecorator,我可以在里面做我需要的逻辑。尽管如此,我仍然需要来自方法的数据,但我无法在 TaskDecorator 中获取这些数据。
@EnableAsync
@Configuration
public class MyAsyncPoolConfig implements AsyncConfigurer {
@Override
@Bean("DefaultAsyncTaskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(0);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("myPrefix");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
异步方法本身。
@Service("TESTCOMPONENT_ASYNC_SERVICE_METHOD_CALL")
@Async("TESTCOMPONENT_ASYNCTESTER_ASYNC_POOL")
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public Future<AsyncCallMethodOutput> asyncMethodCall(AsyncCallMethodInput methodInput) throws MyException {
// actual thing done here
}
这是调用异步方法的地方。
AsyncServiceExampleService asyncServiceExample = SpringApplicationContext.getContext().getBean(AsyncServiceExampleService.class);
我需要访问 AsyncCallMethodInput
参数或更好的参数,@Service
注释的值 ContextAwarePoolExecutor
,ContextAwareCallable
或添加到配置器的 TaskDecorator
.
这可以通过将它们添加到上下文并复制到线程来完成,但我需要在 Executor 或 Callable 中添加这个逻辑,因为这些是通用方法并且可以服务于不同的异步方法。所以我不想强迫方法编写者将额外的数据添加到他们不应该手动更改的上下文中。
有办法实现吗?
我找到了可行的解决方案。可能有更好的解决方案,但这是我能找到的唯一解决方案。
Spring 用另一个 class 包装 Callable<T> task
,后者有一个名为 userDeclaredMethod
的 属性。当我调试时,此方法包含我的 asyncMethodCall
以及我需要的所有元数据。所以我需要做的就是访问这些数据。
经过更多研究,我发现了以下方法,即提取方法。
private static Object getField(Object c, String name) throws IllegalAccessException {
while (c != null && !c.getClass().getName().toLowerCase().equals("java.lang.object")) {
try {
Field field = c.getClass().getDeclaredField(name);
field.setAccessible(true);
return field.get(c);
} catch (NoSuchFieldException e) {
c = c.getClass().getSuperclass();
}
}
return null;
}
当我如下调用此方法时,我能够得到我需要的东西。
Method asyncMethod = (Method) getField(task, "val$userDeclaredMethod");
正如我的旁注,所有这些代码都在 ContextAwarePoolExecutor
class.
我有下面的 类(简化)来使用 Java 和 Spring 工具箱实现异步方法调用。我需要添加一些需要在异步方法调用之前和之后执行的逻辑。
可调用。如果可以访问数据,我可以把我需要的逻辑放在这里。
public class ContextAwareCallable<T> implements Callable<T> {
private Callable<T> task;
private MyContext context;
public ContextAwareCallable(Callable<T> task, MyContext context) {
this.task = task;
this.context = context;
}
@Override
public T call() throws Exception {
return task.call();
}
}
这里是executor,调用task的地方。
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
private static final long serialVersionUID = 1L;
@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable<T>(task, myContext));
}
这是配置器。初始化执行器。据我所知,我可以在这里放一个 TaskDecorator,我可以在里面做我需要的逻辑。尽管如此,我仍然需要来自方法的数据,但我无法在 TaskDecorator 中获取这些数据。
@EnableAsync
@Configuration
public class MyAsyncPoolConfig implements AsyncConfigurer {
@Override
@Bean("DefaultAsyncTaskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(0);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("myPrefix");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
异步方法本身。
@Service("TESTCOMPONENT_ASYNC_SERVICE_METHOD_CALL")
@Async("TESTCOMPONENT_ASYNCTESTER_ASYNC_POOL")
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public Future<AsyncCallMethodOutput> asyncMethodCall(AsyncCallMethodInput methodInput) throws MyException {
// actual thing done here
}
这是调用异步方法的地方。
AsyncServiceExampleService asyncServiceExample = SpringApplicationContext.getContext().getBean(AsyncServiceExampleService.class);
我需要访问 AsyncCallMethodInput
参数或更好的参数,@Service
注释的值 ContextAwarePoolExecutor
,ContextAwareCallable
或添加到配置器的 TaskDecorator
.
这可以通过将它们添加到上下文并复制到线程来完成,但我需要在 Executor 或 Callable 中添加这个逻辑,因为这些是通用方法并且可以服务于不同的异步方法。所以我不想强迫方法编写者将额外的数据添加到他们不应该手动更改的上下文中。
有办法实现吗?
我找到了可行的解决方案。可能有更好的解决方案,但这是我能找到的唯一解决方案。
Spring 用另一个 class 包装 Callable<T> task
,后者有一个名为 userDeclaredMethod
的 属性。当我调试时,此方法包含我的 asyncMethodCall
以及我需要的所有元数据。所以我需要做的就是访问这些数据。
经过更多研究,我发现了以下方法,即提取方法。
private static Object getField(Object c, String name) throws IllegalAccessException {
while (c != null && !c.getClass().getName().toLowerCase().equals("java.lang.object")) {
try {
Field field = c.getClass().getDeclaredField(name);
field.setAccessible(true);
return field.get(c);
} catch (NoSuchFieldException e) {
c = c.getClass().getSuperclass();
}
}
return null;
}
当我如下调用此方法时,我能够得到我需要的东西。
Method asyncMethod = (Method) getField(task, "val$userDeclaredMethod");
正如我的旁注,所有这些代码都在 ContextAwarePoolExecutor
class.