Java 如何使用多态委托创建动态代理?

Java 如何使用多态委托创建动态代理?,java,proxy-classes,Java,Proxy Classes,我想创建一个动态代理,它可以将其方法委托给不同的实现(每个方法调用选择一个可能不同的对象)。我想实现多态效果,比如当某个代理方法调用另一个代理方法时,对象选择机制会再次应用 好了,够混乱了,下面是一个例子: interface IService { void a(); void b(); } class HappyService implements IService { public void a() { System.out.println("Happy a");

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

好了,够混乱了,下面是一个例子:

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
是的,这是因为调用
a()
中的
b()
并不了解动态代理

那么,我如何才能最好地实现我的目标呢?我期望的输出是:

Happy a
Sad b

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

当调用方引用代理而不是“真实”实现时,代理只能用于拦截对象间调用。在这里,
a()
的两个实现都直接调用
b()
,所以它们当然会在
这个
上调用它。您想要做的事情无法通过代理实现

但是,您可以使用AOP来完成,例如使用and(aspectj maven插件也提供)或。大致上,您在
IService
实现中的
a()
b()
方法的基础上创建一个带有切入点的,并建议执行,这可能是用另一个调用替换原始调用。未经测试的代码,但看起来是这样的:

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();
    }
}
然后,您可以直接提供一个
HappyService
SadService
实现作为
iSeries设备
,两者都已修改。您还可以创建一个与
IService
的所有方法相匹配的切入点,并根据方法名称(使用通知中的
thisJoinPoint
)动态进行路由,如您的示例所示


方面也可以使用声明。

呃,我已经尝试了上一段的想法,现在我发现我做不到。所以,我完全被卡住了。我遇到了同样的问题,并用它来创建代理,而不是使用
java.lang.reflect.proxy
。举个例子,谢谢你的回答,弗兰克!恐怕我不能在项目中介绍AspectJ。你知道有什么方面的工具能够解决这个问题,但是除了Java之外没有引入新的语法吗?有一种使用注释的AspectJ语法,但是它们本身包含一些AspectJ语法,很明显。但是,我不知道如何避免这种情况(使用AspectJ或等效工具),除非您自己使用asm或javassist来完成这项工作,因为asm或javassist更容易出错。