我有一个名为A
的接口需要由程序启动后动态加载的类实现。让我们称之为B
。
此接口提供x(多于1个)方法。让我们从a()
调用em到z()
。现在我必须将这个类包装一段时间来测量和控制问题并在它自己的线程中运行它以便能够在需要太长时间时将其杀死。
因此,我发明了包装C
的类B
,因为B
does不能单独实现runnable。
下一部分是原始程序应该调用的类。新类D
。 D
实现接口A
以隐藏模型中的整个控制部分。
现在我必须在D中包装接口的方法并将它们发送到C和C语言,然后将其解包并在对象B上执行它们。
这里有一些我想象的示例代码可以是:
public class D implements A {
private C ai;
public D(String aiName) {
ai = new C("trivialKi");
}
private void call(parameters, ORIGIN_METHOD origin) {
AiTaskExecutor task = new AiTaskExecutor(parameters, origin, ai);
FutureTask<Long> tsk = new FutureTask<Long>(task);
Thread thread = new Thread(tsk);
thread.start();
if (abort) {
tsk.cancel(true);
}
}
@Override
public void a(g g, f f, t t) {
call(g, f, t, ORIGIN_METHOD.a);
}
@Override
public void b(g g, t t, h h) {
call(g, t, h, ORIGIN_METHOD.b);
}
@Override
public void c(g g, t t, f f) {
call(g, t, f, ORIGIN_METHOD.c);
}
}
在C类中,明显的切换案例是使用该枚举将参数传递给类C中的正确方法,该类保存在类C als private字段中。
你有更好的解决方案吗?我个人不喜欢枚举的东西,如果参数太不同,这不会很好。
这样的事情是否有“标准”解决方案?
对此的标准解决方案是:为A使用“动态代理”(java.lang.reflect.Proxy
)。这样可以节省几乎所有的样板代码。
此网站和Google包含足够的Proxy
使用示例。
另外:我建议不要为每次调用使用新线程 - 如果被调用的方法很短,这是非常昂贵的。您可以使用Callable
界面代替Runnable
和线程池Executor
。这也允许你在界面中有返回值:-)
编辑
为了好玩,我编写了动态代理和执行程序的东西。
给出以下接口A
和示例实现B
:
interface A {
int a(int g, int f, int h);
int b(int x);
}
class B implements A {
@Override
public int a(int g, int f, int t) {
System.out.println("called a in thread "+Thread.currentThread().getName());
return 42;
}
@Override
public int b(int x) {
System.out.println("called b in thread "+Thread.currentThread().getName());
return 21;
}
}
一个适当的Callable
使用反射来调用任何java.lang.reflect.Method
看起来像这样:
class ReflectiveMethodCallable implements Callable<Object> {
private Object target;
private Method method;
private Object[] args;
public ReflectiveMethodCallable(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}
@Override
public Object call() throws Exception {
return method.invoke(target, args);
}
}
这样一个ReflectiveMethodCallable
创建并给予ExecutorService
的部分是InvocationHandler
的java.lang.reflect.Proxy
:
class MyInvocationHandler implements InvocationHandler {
private Object target;
private ExecutorService executorService;
public MyInvocationHandler(Object target, ExecutorService executorService) {
this.target = target;
this.executorService = executorService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Callable<Object> task = new ReflectiveMethodCallable(target, method, args);
Future<Object> future = executorService.submit(task);
return future.get();
}
catch(ExecutionException e1){
try {
throw e1.getCause();
} catch(InvocationTargetException e2){
throw e2.getCause();
}
}
}
}
在InvocationHandler
创建一个新的Proxy
时使用createProxyFor
。 Main
类的其余部分用于SSCCE示例:
public class Main {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
// get B somehow
A a = new B();
// get proxy for B
A proxy = createProxyFor(a, executorService);
// call proxy
System.out.println("current thread: "+Thread.currentThread().getName());
int resultA = proxy.a(1,2,3);
System.out.println("calling a returned "+resultA);
int resultB = proxy.b(1);
System.out.println("calling b returned "+resultB);
}
static A createProxyFor(A a, ExecutorService executorService){
InvocationHandler h = new MyInvocationHandler(a, executorService);
A proxy = (A)Proxy.newProxyInstance(A.class.getClassLoader(), new Class[]{A.class}, h);
return proxy;
}
}
输出:
current thread: main
called a in thread pool-1-thread-1
calling a returned 42
called b in thread pool-1-thread-1
calling b returned 21
完成:
A
中的每个方法都将在另一个线程中调用。invoke
或call
中完成。