在运行时重定向方法调用以引入某种沙箱

时间:2015-08-18 18:04:07

标签: java java-7

我已经解决了这个问题。希望获得银弹。

我有几个单身(~10),它们都有一些功能(每个约10个)。我的函数调用看起来像这样(他们应该这样)。 注意:大多数这些调用都是异步的,不会返回任何内容。只有少数是同步的

SingletonClassGorrilla.getInstance().methodSwim(swimmingPool, lifeJacket, whistle);
SingletonClassRacoon.getInstance().methodBark(thief, owner);

我需要将所有这些调用放在沙盒中:

Sandbox.runThisInSandboxMode(new Runnable{
    @Override
    public void run(){
        SingletonClassGorrilla.getInstance().methodSwim(swimmingPool, lifeJacket, whistle);
    }
});

由于他们被调用的地方数量巨大,我希望单身人士可以实现sandboxMode

可能的解决方案(但由于我必须像这样包装的函数数量不可行):

public class SingletonClassGorrilla{
    public void methodSwim(WaterBody waterBody, Instrument instrument, 
            EmResponse emResponse){

        Sandbox.runThisInSandboxMode(new Runnable{
            @Override
            public void run(){
                methodSwim(swimmingPool, lifeJacket, whistle, true);
            }
        });

    }

    private void methodSwim(WaterBody waterBody, Instrument instrument, 
            EmResponse emResponse, boolean fromSandbox){

        // Do your thang.

    }
}

无论如何,通过使用语言中的反射/注释/任何其他东西,可以减少所需的更改量吗?

2 个答案:

答案 0 :(得分:1)

您可以使用合适InvocationHandler的{​​{3}}(但您必须为每个单身人士提取interface)。免责声明:我还没有尝试过编译/运行此代码,但它应该给你一般的想法。如果您关心单身人士的返回值,则可能必须在沙盒界面中使用Callable代替/ Runnable

public class SingletonGorilla implements GorillaInterface {
  private static SingletonGorilla theRealGorilla;
  public static GorillaInterface getInstance() {
    //In reality, you'd want to store off the Proxy as well
    return Proxy.newProxyInstance(SingletonGorilla.class.getClassLoader(), GorillaInterface.class, new SandboxingHandler());
  }

  private static class SandboxingHandler implements InvocationHandler () {
  public Object invoke(Object proxy, Method method, Object[] args) {
    return Sandbox.runInSandbox( new Runnable() {
      public void run () {
        method.invoke(proxy, args));
      }
    }
  }
}

答案 1 :(得分:0)

我正在考虑以下几点: 首先,您需要为每个单身人士提供一个界面:

接口:

package org.test.proxywrapper;

public interface IGorilla {

    public void methodSwim();

}

实施班级:

package org.test.proxywrapper;

public class Gorilla implements IGorilla{

    public void methodSwim()
    {

    }
}

然后,实现一个InvocationHandler,它会对每次调用Gorilla方法时常见的代码进行分解:

package org.test.proxywrapper;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class WrapperInvocationHandler implements InvocationHandler {

    @Override
    public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {

        Sandbox.runThisInSandboxMode(new Runnable() {
            @Override
            public void run() {
                Object params = new Object[0];
                try {
                    arg1.invoke(arg0, new Object[]{});
                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        });
        // return something if you need to
        return new Object();
    }
}

此时,在应用程序/系统的中心位置,使用Proxy包装每个单例,并传递代理引用而不是原始包装对象:

package org.test.proxywrapper;

import java.lang.reflect.Proxy;

public class Main {

    public static void main(String argv[])
    {
        WrapperInvocationHandler wrapperInvocationHandler =  new WrapperInvocationHandler();
        Class<?>[] implementedTypes = new Class<?>[1];
        implementedTypes[0] = IGorilla.class;
        IGorilla proxy = (IGorilla) Proxy.newProxyInstance(Main.class.getClassLoader(), implementedTypes, wrapperInvocationHandler);
        proxy.methodSwim();
    }
}

这个简单的例子按照我的预期编译和运行。 我在这里剪了一些角,跳过了getInstance方法等,但我想它会让我知道它是如何完成的。