如何创建动态代理链?

时间:2016-09-02 01:59:34

标签: java design-patterns

我创建了两个InvocationHandler,一个用于记录目的,另一个用于测量时间。每个都在工作,但我不知道如何创建这两个链,以便两者都将被执行。我认为只要LoggingInvocationHandler扩展TimerInvocationHandler就足够了

    public class DynamicProxyMain {

public static void main(String[] args) {
    System.out.println("Starting dynamic proxy sample");

    SubjectInterface timerProxy = (SubjectInterface) Proxy.newProxyInstance(SubjectInterface.class.getClassLoader(),
            new Class<?>[]{SubjectInterface.class},
            new TimerInvocationHandler(new SubjectInterfaceImpl()));

    SubjectInterface logginProxy = (SubjectInterface) Proxy.newProxyInstance(SubjectInterface.class.getClassLoader(),
            new Class<?>[]{SubjectInterface.class},
            new LoggingInvocationHandler(new SubjectInterfaceImpl()));
    timerProxy.methodA("a");
    timerProxy.methodB("test b");
    timerProxy.methodC(1, "test c");

}
}

public class LoggingInvocationHandler implements InvocationHandler {
Object impl;
String CLASSNAME = this.getClass().getCanonicalName();

public LoggingInvocationHandler(Object impl){
    this.impl = impl;

}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object retVal;
    System.out.println("LoggingHandler:" + this.getClass().getName() + " has been called");
    retVal = method.invoke(impl, args);
    System.out.println("LoggingHandler:" + this.getClass().getName() + " has ended");
    return retVal;

}
}


 public class TimerInvocationHandler extends LoggingInvocationHandler          implements InvocationHandler{
private Object impl;

public TimerInvocationHandler(Object impl) {
    super(impl);
    this.impl = impl;
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    Object retVal = null;
    System.out.println("getting duration time for method " + method.getName());
    long duration = -System.currentTimeMillis();
    retVal = super.invoke(proxy,method,args);
    duration += System.currentTimeMillis();
    System.out.println("it took " + duration + " milliseconds");
    System.out.println("duration time handler has ended");
    return retVal;
}
}

实际上我解决了它,因此将调用两个InvocationHandler。我使用当前正在运行的代码编辑了我的帖子

2 个答案:

答案 0 :(得分:2)

这个想法与Intercepting Filter有相似之处,我会给你一个实现它,如果你有兴趣和想要,我会稍加修改以便与DynamicProxyHandler一起使用更多细节,您应该彻底阅读link

<强>参与者

  • InvocationChain - 负责调度调用。
  • Invocation - 你应该放置loggingtimer之类的内容。
  • DynamicProxyHanlder - 只需将请求委托给InvocationChain

<强> Implementaiton

DynamicProxyHandler.java

public class DynamicProxyHandler implements InvocationHandler {
    private Object proxied;
    InvocationChain chain = new InvocationChainImp();

    DynamicProxyHandler(Object proxied) {
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return chain.invoke(proxied, method, args);
    }

}

Invocation.java

public interface Invocation {
    Object invoke(Object callee, Method method, Object[] args, InvocationChain chain);
}

InvocationChain.java

public interface InvocationChain {
    public Object invoke(Object callee, Method method, Object[] args);
}

InvocationChainImp.java

public class InvocationChainImp implements InvocationChain {
    List<Invocation> list = new ArrayList<>();
    Object result;
    Iterator<Invocation> tasks;

    InvocationChainImp() {
        list.add(new LoggingInvocation());
        list.add(new TimerInvocation());
        list.add(new FinalInvocation());
        tasks = list.iterator();
    }

    @Override
    public Object invoke(Object callee, Method method, Object[] args) {
        if (tasks.hasNext()) {
            Object result = tasks.next().invoke(callee, method, args, this);
            this.result = (this.result == null ? result : this.result);
        }
        return this.result;
    }

最后,我们要定义一些必须限制在Invocation接口的自定义类,以便记录,计时器等。

LoggingInvocation.java

public class LoggingInvocation implements Invocation {
    @Override
    public Object invoke(Object callee, Method method, Object[] args, InvocationChain chain) {
        chain.invoke(callee, method, args);
        Logger.getLogger(this.getClass().getCanonicalName()).info(method.getName() + "() execution logged!");
        return null;
    }
}

TimerInvocation.java

public class TimerInvocation implements Invocation {
    @Override
    public Object invoke(Object callee, Method method, Object[] args, InvocationChain chain) {
        long start_time = System.nanoTime();
        chain.invoke(callee, method, args);
        long end_time = System.nanoTime();

        System.out.println("Timer: excution took " + (end_time - start_time) / 1e6 + "ms");

        return null;
    }
}

FinalInvocation.java ,最后在代理实例上调用请求。

public class FinalInvocation implements Invocation {
    @Override
    public Object invoke(Object callee, Method method, Object[] args, InvocationChain chain) {
        try {
            return method.invoke(callee, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return null;
    }
}

其余的代码是微不足道的,因为它只是用于证明实现的有效性 如果您想自己编写,可以立即停止阅读

SubjectInterface.java

public interface SubjectInterface {
    String hello();
}

SubjectInterfaceImp.java

public class SubjectInterfaceImp implements SubjectInterface {
    @Override
    public String hello() {
        System.out.println("in SubjectInterfaceImp: Greeting!");
        return "hello";
    }
}

Main.java

public class Main {
    public static void main(String[] args) throws Exception {
        SubjectInterface subject = (SubjectInterface) Proxy.newProxyInstance(
                SubjectInterface.class.getClassLoader(),
                new Class[] { SubjectInterface.class }, new DynamicProxyHandler(new SubjectInterfaceImp()));
        System.out.println("in Main: subject.hello() = " + subject.hello());
    }
}

好的,我们有足够的代码,它的演出时间,让我们看看 voila

in SubjectInterfaceImp: Greeting!
Timer: excution took 0.532198ms
九月 02, 2016 12:37:36 下午 LoggingInvocation invoke
信息: hello() execution logged!
in Main: subject.hello() = hello

答案 1 :(得分:0)

这不是实现它的自然方式.TimerInvocationHandler与LoggingInvocationHandler无关。 定义一个装饰器,它是一个InvocationHandler并包装另一个InovovationHandler

https://en.wikipedia.org/wiki/Decorator_pattern

编辑:由于一条评论要求我提供一个示例实现,添加了以下部分,但这不是精确的装饰模式,但我认为其他人可以理解解决方案。在这种情况下,TimeInvocationHandler不限于测量登录时间

public class TimerInvocationHandler implements InvocationHandler
{
  protected InvocationHandler invocationHandler;

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  {
    //do whatever you want
    Object result = invocationHandler.invoke(proxy, method, args);
    // do what ever you want
    return result;
  }
}