Skip to content
Danila Rassokhin edited this page Jan 27, 2023 · 1 revision

Proxy classes and objects

In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes.

MethodInterceptor

MethodInterceptor defines interceptor behavior for method interception. It has only one method intercept:

  • returns Object - result of method call
  • it accepts original method, proxy method, proxy object from which method was called and parameters with which method was called

Example

public class LoggerMethodInterceptor implements MethodInterceptor {
  @Override
  public Object intercept(Method proxyMethod, Method originMethod, Object proxy, Object... args)
      throws InvocationTargetException, IllegalAccessException {
    BasicComponentManager.getGameLogger().info("METHOD " + originMethod.getName() + " INVOKED");
    return proxyMethod.invoke(proxy, args);
  }
}

ProxyCreator

ProxyCreator is an interface which defines behavior of proxy creation mechanism in Progressive. It has basic implementation called BasicProxyCreator which uses ByteBuddy for proxy creation. ProxyCreator can create both proxy classes and proxy objects from their originals, which can intercept method calls from originals.

Proxy classes

ProxyCreator can create proxy classes from some basic classes. You can create proxy classes in 2 ways:

  • with ComponentCreator.create()
  • with ProxyCreator.createProxy()

Create proxy using ComponentCreator

To create proxy using ComponentCreator you need to annotate your class with Proxy and specify MethodInterceptor implementation class. You also need to annotate methods which must be intercepted with @Intercept. This type of proxy creation will be useful when you creating proxy from your classes and you can make changes in them.

Create proxy using ProxyCreator

To create proxy using ProxyCreator you don't need any annotations, just call ProxyCreator.create(). All methods of source class will be intercepted then.

Example

Create MethodInterceptor:

@Proxy(LoggerMethodInterceptor.class)
public class TestProxyBean {

  @Autofill
  public TestProxyBean(@Qualifier("simpleGameItem") GameItem gameItem) {
    BasicComponentManager.getGameLogger().info("TEST PROXY CONSTRUCTOR: " + gameItem);
  }

  @Intercept
  public void print(String a) {
    BasicComponentManager.getGameLogger().info(a);
  }

  @Intercept
  public int getInt(int a) {
    BasicComponentManager.getGameLogger().info("GET INT = " + a);
    return a;
  }

  public void notIntercepted(String message) {
    BasicComponentManager.getGameLogger().info(message);
  }
}

Create some class to create proxy from:

@Proxy(LoggerMethodInterceptor.class)
public class TestProxyBean {

  @Autofill
  public TestProxyBean(@Qualifier("simpleGameItem") GameItem gameItem) {
    BasicComponentManager.getGameLogger().info("TEST PROXY CONSTRUCTOR: " + gameItem);
  }

  @Intercept
  public void print(String a) {
    BasicComponentManager.getGameLogger().info(a);
  }

  @Intercept
  public int getInt(int a) {
    BasicComponentManager.getGameLogger().info("GET INT = " + a);
    return a;
  }

  public void notIntercepted(String message) {
    BasicComponentManager.getGameLogger().info(message);
  }
}

Now create proxy:

public class ProxyExample {

  public ProxyExample() {
    // Create proxy bean
    // if class annotated as @Proxy
    TestProxyBean proxyBean = BasicComponentCreator.create(TestProxyBean.class);
    // These methods will be intercepted, cause they are @Intercepted
    proxyBean.print("Hello");
    int a = proxyBean.getInt(1);
    assert a == 1;
    // This method won't be intercepted, cause it's not @Intercepted
    proxyBean.notIntercepted("Not intercepted");

    // if class is not annotated as @Proxy
    GameItem proxyBean1 =
        BasicComponentManager.getProxyCreator()
            .createProxy(GameItem.class, new LoggerMethodInterceptor());
    // All methods will be intercepted
    proxyBean1.setName("itemName");
  }
}