Storia della domanda:
Il Dynamic Proxy Pattern è emerso in Java 1.3 e ha permesso di implementare modelli AOP, logging, sicurezza, generazione dinamica di codice senza la necessità di scrivere manualmente classi proxy. Questo è diventato molto popolare in Spring, Hibernate e altri framework.
Problema:
A volte è necessario aggiungere funzionalità a un'interfaccia esistente o modificare il comportamento dei metodi durante l'esecuzione, senza modificare il codice sorgente. Esempio: registrazione di ogni chiamata al metodo, controllo degli accessi, profilazione. Il principale problema è che non è possibile farlo manualmente per tutte le classi, specialmente se ci sono molte classi o se vengono generate dinamicamente.
Soluzione:
Java fornisce un'API standard nel pacchetto java.lang.reflect per creare oggetti proxy "al volo" per qualsiasi interfaccia utilizzando Proxy.newProxyInstance. Viene implementato l'oggetto InvocationHandler, che gestisce ogni chiamata al metodo e implementa la propria logica.
Esempio di codice:
import java.lang.reflect.*; interface Service { void serve(); } class ServiceImpl implements Service { public void serve() { System.out.println("Serving..."); } } class LoggingHandler implements InvocationHandler { private final Object target; public LoggingHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Calling " + method.getName()); return method.invoke(target, args); } } Service service = (Service) Proxy.newProxyInstance( Service.class.getClassLoader(), new Class[]{Service.class}, new LoggingHandler(new ServiceImpl())); service.serve();
Caratteristiche principali:
È possibile "avvolgere" una classe normale, che non implementa interfacce, usando un dynamic proxy standard?
No. Il Dynamic Proxy funziona solo con interfacce. Per le classi è necessaria la manipolazione del bytecode (ad esempio, CGLIB).
Cosa succede se l'interfaccia contiene metodi con tipi di ritorno incompatibili con il valore di ritorno dell'InvocationHandler?
Verrà sollevata un'eccezione ClassCastException, quindi il valore di ritorno deve essere strettamente compatibile con la definizione dell'interfaccia.
È possibile usare dynamic proxy per metodi finali?
No. Il Proxy funziona solo a livello di interfacce, e non ci sono metodi finali lì. I metodi finali non possono essere sovrascritti.
Caso negativo
Un sviluppatore ha tentato di implementare il logging di audit tramite Proxy su classi senza interfaccia.
Vantaggi:
Svantaggi:
Caso positivo
Hanno definito un contratto tramite interfaccia, già creato un wrapper proxy per essa.
Vantaggi:
Svantaggi: