4

我想创建一个动态代理,它可以将其方法委托给不同的实现(每个方法调用选择一个可能不同的对象)。而且我想实现多态的效果,比如当某个代理方法调用另一个代理方法时,对象选择机制确实再次适用。

好的,足够的混乱,这是一个例子:

interface IService {
  void a();
  void b();
}

class HappyService implements IService {
  public void a() {
    System.out.println("Happy a");
    b();
  }

  public void b() {
    System.out.println("Happy b");
  }
}

class SadService implements IService {
  public void a() {
    System.out.println("Sad a");
    b();
  }

  public void b() {
    System.out.println("Sad b");
  }
}

现在,我想创建一个代理,IService它总是选择HappyService方法调用和a()方法SadService调用b()。这是我首先想到的:

InvocationHandler h = new InvocationHandler() {
  @Override
  public Object invoke( final Object proxy, final Method method, final Object[] args ) throws Throwable {
    Object impl;
    if (method.getName().equals("a")) {
      impl = new HappyService();
    } else if (method.getName().equals("b")) {
      impl = new SadService();
    } else {
      throw new IllegalArgumentException("Unsupported method: " + method.getName());
    }
    return method.invoke(impl, args);
  }
};
IService service = (IService)Proxy.newProxyInstance( IService.class.getClassLoader(), new Class[]{ IService.class }, h );
service.a();

这打印:

Happy a
Happy b

是的,那是因为调用b()inside ofa()对动态代理一无所知。

那么,我怎样才能最好地实现我的目标呢?我想要的输出是:

Happy a
Sad b

我可能会用new HappyService()另一个代理替换调用处理程序内部的我,它只将方法传递a()HappyService,并将所有其他方法重定向回原始代理。但也许有更好/更简单的解决方案?

4

1 回答 1

3

当调用者引用代理而不是“真实”实现时,代理只能用于拦截对象间调用。在这里,你的a()call实现都是b()直接的,所以他们当然会调用它 on this。你想做的事情不能通过代理来实现。

但是,您可以使用 AOP 来实现,例如使用AspectJ编译时编织(也可用于 aspectj-maven-plugin)或加载时编织粗略地说,您在实现中的和方法的调用站点上创建一个切入点,并建议执行,这可能是将原始调用替换为另一个。未经测试的代码,但它看起来像这样:a()b()IService

public aspect IServiceAspect {
    private IService happy = new HappyService(); // Assuming these are stateless services
    private IService sad = new SadService();     // that can be shared.

    // The pointcut is inside an IService implementation, and is a call to the a() method
    pointcut aCall(): within(IService+) && call(* IService.a());

    pointcut bCall(): within(IService+) && call(* IService.b());

    around(): aCall() && !within(HappyService) { // To avoid infinite recursion
        return happy.a();
    }

    around(): bCall() && !within(SadService) {
        return sad.b();
    }
}

然后,您可以直接提供一个HappyServiceSadService实现作为一个IService,两者都已修改。您还可以创建与 的所有方法匹配的单个切入点IService,并根据方法名称(thisJoinPoint在建议中使用)动态地进行路由,就像在您的示例中一样。

方面也可以使用注释来声明。

于 2012-10-12T12:01:37.763 回答