java - que - ¿Qué son las clases Dynamic Proxy y por qué debería usar una?
jframe (5)
¿Qué es un caso de uso para usar un proxy dinámico?
¿Cómo se relacionan con la generación y reflexión de bytecode?
¿Alguna lectura recomendada?
Una clase de proxy dinámico es una clase que implementa una lista de interfaces especificadas en tiempo de ejecución de modo que una invocación de método a través de una de las interfaces en una instancia de la clase será codificada y enviada a otro objeto a través de una interfaz uniforme. Se puede usar para crear un objeto proxy de seguridad de tipos para una lista de interfaces sin requerir la pregeneración de la clase proxy. Las clases de proxy dinámico son útiles para una aplicación o biblioteca que necesita proporcionar despacho reflectante seguro de tipo de invocaciones en objetos que presentan interfaces API.
Acabo de encontrar un uso interesante para un proxy dinámico.
Estábamos teniendo algunos problemas con un servicio no crítico que está acoplado con otro servicio dependiente y queríamos explorar formas de ser tolerantes a fallas cuando ese servicio dependiente deja de estar disponible.
Así que escribí un LoadSheddingProxy que toma dos delegados, uno es el impl remoto para el servicio ''normal'' (después de la búsqueda JNDI). El otro objeto es una impl de pérdida de carga ''ficticia''. Hay una lógica simple que rodea cada invocación de método que atrapa los tiempos de espera y se desvía al maniquí durante un cierto período de tiempo antes de reintentar. Así es como lo uso:
// This is part of your ServiceLocator class
public static MyServiceInterface getMyService() throws Exception
{
MyServiceInterface loadShedder = new MyServiceInterface() {
public Thingy[] getThingys(Stuff[] whatever) throws Exception {
return new Thingy[0];
}
//... etc - basically a dummy version of your service goes here
}
Context ctx = JndiUtil.getJNDIContext(MY_CLUSTER);
try {
MyServiceInterface impl = ((MyServiceHome) PortableRemoteObject.narrow(
ctx.lookup(MyServiceHome.JNDI_NAME),
MyServiceHome.class)).create();
// Here''s where the proxy comes in
return (MyService) Proxy.newProxyInstance(
MyServiceHome.class.getClassLoader(),
new Class[] { MyServiceInterface.class },
new LoadSheddingProxy(MyServiceHome.JNDI_NAME, impl, loadShedder, 60000)); // 10 minute retry
} catch (RemoteException e) { // If we can''t even look up the service we can fail by shedding load too
logger.warn("Shedding load");
return loadShedder;
} finally {
if (ctx != null) {
ctx.close();
}
}
}
Y aquí está el proxy:
public class LoadSheddingProxy implements InvocationHandler {
static final Logger logger = ApplicationLogger.getLogger(LoadSheddingProxy.class);
Object primaryImpl, loadDumpingImpl;
long retry;
String serviceName;
// map is static because we may have many instances of a proxy around repeatedly looked-up remote objects
static final Map<String, Long> servicesLastTimedOut = new HashMap<String, Long>();
public LoadSheddingProxy(String serviceName, Object primaryImpl, Object loadDumpingImpl, long retry)
{
this.serviceName = serviceName;
this.primaryImpl = primaryImpl;
this.loadDumpingImpl = loadDumpingImpl;
this.retry = retry;
}
public Object invoke(Object obj, Method m, Object[] args) throws Throwable
{
try
{
if (!servicesLastTimedOut.containsKey(serviceName) || timeToRetry()) {
Object ret = m.invoke(primaryImpl, args);
servicesLastTimedOut.remove(serviceName);
return ret;
}
return m.invoke(loadDumpingImpl, args);
}
catch (InvocationTargetException e)
{
Throwable targetException = e.getTargetException();
// DETECT TIMEOUT HERE SOMEHOW - not sure this is the way to do it???
if (targetException instanceof RemoteException) {
servicesLastTimedOut.put(serviceName, Long.valueOf(System.currentTimeMillis()));
}
throw targetException;
}
}
private boolean timeToRetry() {
long lastFailedAt = servicesLastTimedOut.get(serviceName).longValue();
return (System.currentTimeMillis() - lastFailedAt) > retry;
}
}
La clase java.lang.reflect.Proxy
permite implementar interfaces dinámicamente mediante el manejo de llamadas a métodos en un InvocationHandler
. Se considera parte de la función de reflexión de Java, pero no tiene nada que ver con la generación de código byte.
Sun tiene un tutorial sobre el uso de la clase Proxy. Google también ayuda.
Recomiendo este resource .
En primer lugar, debe comprender el caso de uso del patrón de proxy. Recuerde que la intención principal de un proxy es controlar el acceso al objeto de destino, en lugar de mejorar la funcionalidad del objeto de destino. El control de acceso incluye sincronización, autenticación, acceso remoto (RPC), instanciación diferida (Hibernate, Mybatis), AOP (transacción).
En contraste con el proxy estático, el proxy dinámico genera bytecode que requiere la reflexión de Java en tiempo de ejecución. Con Dynamic, no es necesario que cargues la clase proxy, lo que puede brindarte más comodidad.
Un caso de uso es Hibernate: le proporciona objetos que implementan su interfaz de clases de modelo, pero en getters y setters reside el código relacionado con db. Es decir, los usa como si fueran simples POJO, pero en realidad están sucediendo muchas cosas ocultas.
Por ejemplo, usted simplemente llama a un getter de propiedad cargada de forma perezosa, pero realmente la propiedad (probablemente toda la estructura de objetos grandes) se obtiene de la base de datos.
Debería consultar la biblioteca cglib para obtener más información.