什么是dynamic代理类,为什么要使用它?
什么是使用dynamic代理的用例?
它们如何与字节码生成和reflection相关联?
任何推荐阅读?
我强烈推荐这个资源 。
首先,你必须明白什么是代理模式的用例。 请记住,代理的主要目的是控制对目标对象的访问,而不是增强目标对象的function。 访问控制包括同步,authentication,远程访问(RPC),懒惰实例(Hibernate,Mybatis),AOP(事务)。
与静态代理相比,dynamic代理生成的字节码在运行时需要Javareflection。 dynamic的,你不需要创build代理类,这可以带来更多的便利。
dynamic代理类是一个实现在运行时指定的接口列表的类,使得通过类的实例中的一个接口的方法调用将被编码并通过统一的接口分派到另一个对象。 它可用于为接口列表创buildtypes安全的代理对象,而无需预先生成代理类。 dynamic代理类对于需要在呈现接口API的对象上提供types安全的调用调用的应用程序或库很有用。
dynamic代理类
我刚刚提出了一个有趣的dynamic代理使用。
我们遇到了一些与非关键服务相关的服务,这些服务与另一个相关服务结合在一起,并且想要探索在相关服务不可用时的容错方式。
所以我写了一个LoadSheddingProxy接受两个委托 – 一个是“正常”服务的远程impl(在JNDI查找之后)。 另一个对象是一个“虚拟”卸载impl。 围绕每个方法调用的简单逻辑可以捕获超时并在重试之前转移到虚拟机一段时间。 以下是我如何使用它:
// 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(); } } }
这里是代理:
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; } }
类java.lang.reflect.Proxy
允许您通过在InvocationHandler
处理方法调用来dynamic实现接口。 它被认为是Javareflection工具的一部分,但与字节码生成无关。
Sun有一个关于使用Proxy类的教程 。 Google也会帮助你。
一个用例是hibernate – 它给你实现你的模型类接口的对象,但在getters和setters那里驻留数据库相关的代码。 也就是说,你使用它们,就好像它们只是简单的POJO一样,但实际上有很多事情是在掩护下进行的。
例如 – 你只需要调用一个lazily加载属性的getter,但是真正的属性(可能是整个大对象结构)从数据库中获取。
你应该检查cglib库了解更多信息。