2009-06-01 93 views

回答

13

我强烈推荐这个resource

首先,你必须了解什么是代理模式的用例。请记住,代理的主要目的是控制对目标对象的访问,而不是增强目标对象的功能。访问控制包括同步,身份验证,远程访问(RPC),懒惰实例化(Hibernate,Mybatis),AOP(事务)。

与静态代理相比,动态代理生成的字节码在运行时需要Java反射。动态的你不需要创建代理类,这可以带来更多的便利。

+0

和链接被破坏 – bvdb 2016-05-15 15:56:40

5

一个用例是hibernate--它为您提供了实现您的模型类接口的对象,但是在getters和setters下面存在与db相关的代码。即你使用它们就好像它们只是简单的POJO一样,但实际上有很多事情正在掩盖之中。

例如 - 你只需调用lazily加载的属性的getter,但真正的属性(可能是整个大对象结构)从数据库中获取。

您应该检查cglib库以获取更多信息。

28

动态代理类是实现在运行时指定的 接口的列表,使得通过对类的一个实例的接口 一个将被编码和 方法调用调度到另一个类通过统一的界面对象。它可以是 ,用于为接口列表创建类型安全的代理对象 ,无需预先生成代理类。动态代理 类对于需要提供 类型安全的对调用接口API的对象的反射调度的应用程序或库很有用。

Dynamic Proxy Classes

+0

好的答案,这个事情的一个很好的例子是Spring Remoting,它内置了HTTP,RMI,EJB和JMS的代理功能。 – Robin 2009-06-01 13:39:53

16

我只是想出了一个动态代理一个有趣的使用。

我们遇到了一些与非关键服务相关的服务,这些服务与另一个相关服务结合在一起,并且希望探索在相关服务不可用时的容错方式。

所以我写了一个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; 
} 
} 
相关问题