DynamicProxyBuilder

The fluent builder behind every runtime proxy in ProxyBuilder.

DynamicProxyBuilder is the entry point for the runtime side. It produces a JDK dynamic proxy that implements the target interface and routes every call through the configured hooks before reaching your implementation.

Construction

DynamicProxyBuilder<Service> builder =
    DynamicProxyBuilder.createBuilder(Service.class, new ServiceImpl());

The two arguments are the interface type and the concrete implementation instance. The builder is generic on the interface, so the result of .build() is typed as Service.

Pre and post actions

A pre-action runs before each method invocation. A post-action runs after.

Service proxy = DynamicProxyBuilder
    .createBuilder(Service.class, new ServiceImpl())
    .addIPreAction((original, method, args) -> {
      // original is the wrapped instance
      // method is the java.lang.reflect.Method being called
      // args is the argument array
    })
    .addIPostAction((original, method, args) -> {
      // same signature, runs after the real call
    })
    .build();

Multiple addIPreAction/addIPostAction calls compose. They run in registration order: pre-actions in the order you added them, post-actions in the same order.

Chaining additional behaviour

The builder is fluent and idempotent:

Service proxy = DynamicProxyBuilder
    .createBuilder(Service.class, new ServiceImpl())
    .addIPreAction(beforeHook)
    .addSecurityRule(currentUserHasPermission)
    .addMetrics()
    .addLogging()
    .addIPostAction(afterHook)
    .build();

Each method returns the same builder, so order in the chain only matters for hook execution order (pre/post), not for which features are enabled.

What the proxy is

build() returns an instance of the interface, backed by a JDK dynamic proxy. Pass it to any consumer that expects the interface:

Service service = DynamicProxyBuilder
    .createBuilder(Service.class, new ServiceImpl())
    .addMetrics()
    .build();

myComponent.doWorkWith(service);   // myComponent never knows it is a proxy

Limitations

  • Interfaces only. The proxy implements an interface; it cannot extend an arbitrary class. If you need that, look at the compile-time static proxies instead.
  • Method-level scoping is global. Every method on the interface goes through every hook. If you need per-method behaviour, branch inside the hook on method.getName() or method.getAnnotation(...).
  • Reflection at runtime. This is JDK-standard reflection, which means GraalVM native image needs a reflection configuration entry for the interface. If that is a problem, use the static processors.

Next

Edit this page on GitHub ↗