Um proxy dinâmico em Java permite interceptar chamadas a métodos de um objeto real, adicionando comportamentos adicionais como log, autorização ou medição de tempo sem modificar a implementação original. Isso é feito com base na API de reflexão e na enterface java.lang.reflect.InvocationHandler.
A seguir, apresentamos uma implementação personalizada de proxy dinâmico que permite configurar ações antes e após a execução dos métodos do objeto alvo, além de mensagens customizadas e controle sobre o retorno do proxy.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
public class CustomDynamicProxy implements InvocationHandler {
private Object target;
private String[] preMessages;
private String[] postMessages;
private Set<MethodCall> preActions = new HashSet<>();
private Set<MethodCall> postActions = new HashSet<>();
private Set<String> methodsReturningProxy = new HashSet<>();
public CustomDynamicProxy(Object target) {
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
executePreMessages();
executePreActions();
Object result = method.invoke(target, args);
executePostMessages();
executePostActions();
return shouldReturnProxy(method.getName()) ? proxy : result;
}
private void executePreMessages() {
if (preMessages != null) {
for (String msg : preMessages) {
if (msg != null && !msg.trim().isEmpty()) {
System.out.println(msg);
}
}
}
}
private void executePostMessages() {
if (postMessages != null) {
for (String msg : postMessages) {
if (msg != null && !msg.trim().isEmpty()) {
System.out.println(msg);
}
}
}
}
private void executePreActions() {
performActions(preActions);
}
private void executePostActions() {
performActions(postActions);
}
private void performActions(Set<MethodCall> actions) {
if (actions == null || actions.isEmpty()) return;
for (MethodCall call : actions) {
try {
call.getMethod().invoke(call.getInstance(), call.getArgs());
} catch (Exception e) {
System.err.println("Erro ao executar ação: " + e.getCause().getMessage());
e.printStackTrace();
}
}
}
public void setPreMessages(String... messages) {
this.preMessages = messages;
}
public void setPostMessages(String... messages) {
this.postMessages = messages;
}
public void addPreAction(Method method, Object instance, Object... args) {
preActions.add(new MethodCall(method, instance, args));
}
public void addPostAction(Method method, Object instance, Object... args) {
postActions.add(new MethodCall(method, instance, args));
}
public void markMethodToReturnProxy(String methodName) {
methodsReturningProxy.add(methodName);
}
private boolean shouldReturnProxy(String methodName) {
return methodsReturningProxy.contains(methodName);
}
private static class MethodCall {
private final Method method;
private final Object instance;
private final Object[] args;
MethodCall(Method method, Object instance, Object... args) {
this.method = method;
this.instance = instance;
this.args = args;
}
Method getMethod() { return method; }
Object getInstance() { return instance; }
Object[] getArgs() { return args; }
}
}
Para demonstrar o uso, definimos uma interface simples Person e duas implementações:
public interface Person {
void name();
}
public class XiaoMing implements Person {
@Override
public void name() {
System.out.println("===== Eu sou o XiaoMing =====");
}
}
public class XiaoHong implements Person {
@Override
public void name() {
System.out.println("===== Eu sou a XiaoHong =====");
}
}
Classe de teste para validar o comportamento do proxy:
public class ProxyTest {
public static void main(String[] args) {
try {
XiaoMing xiaoMing = new XiaoMing();
XiaoHong xiaoHong = new XiaoHong();
CustomDynamicProxy proxyHandler = new CustomDynamicProxy(xiaoMing);
Person proxy = (Person) proxyHandler.getProxy();
// Configura ações antes e depois usando o método 'name' de XiaoHong
proxyHandler.addPreAction(
xiaoHong.getClass().getMethod("name"),
xiaoHong
);
proxyHandler.addPostAction(
xiaoHong.getClass().getMethod("name"),
xiaoHong
);
// Executa o método através do proxy
proxy.name();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Saída esperada ao executar ProxyTest:
===== Eu sou a XiaoHong =====
===== Eu sou o XiaoMing =====
===== Eu sou a XiaoHong =====
Este exemplo mostra como o proxy dinâmico pode orquestrar chamadas a métodos reais com lógica adicional ao redor, utilizando reflexão para invocar métodos em tempo de execução. O mecanismo opera exclusivamente nos pontos antes e depois da execução do método — não é possível inserir lógica no interior do método original sem bytecode manipulation.