其他分享
首页 > 其他分享> > 如何使用多态委派创建动态代理?

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

作者:互联网

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

好吧,有足够的困惑,这是一个例子:

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()并不知道有关动态代理的任何信息.

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

Happy a
Sad b

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

解决方法:

当调用者具有对代理的引用而不是“真实”实现时,代理只能用于拦截对象间调用.在这里,你的a()实现都直接调用b(),所以当然他们就这样调用它.代理人无法实现您想要做的事情.

但是,您可以使用AOP来完成,例如使用AspectJcompile-time weaving(也可以使用aspectj-maven-plugin)或load-time weaving.粗略地说,您在a()和b()的calling sites上创建带有切入点的aspect 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();
    }
}

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

方面也可以使用annotations声明.

标签:java,proxy-classes
来源: https://codeday.me/bug/20190630/1332377.html