Java模式中的静态代理与动态代理

某些接口的实现类,我们要做一个代理,来代理对这些实现类对象的方法调用。


该类的简单代理


使用代理的原因

public  class  SomeClassImpl  {
  
private String userName;  
  
public SomeClassImpl(final String userName) {
    
this.userName = userName;
  }
    
    
public void someMethod( ) {
    System.out.println(
this.userName);
  }

  
public void someOtherMethod(final String text) {
    System.out.println(text);
  }

}

 

public  class  SomeClassProxy  {
  
private final SomeClassImpl impl;
  
public SomeClassProxy(final SomeClassImpl impl) {
    
this.impl = impl;
  }


  
public void someMethod( ) {
    
this.impl.someMethod( );
  }

  
public void someOtherMethod(String text) {
    
this.impl.someOtherMethod(text);
  }

}

 

有一些原因,你需要做代理来在你的应用和实现类之间插入一些有用的代码。
1.实现类的源码不能拿到。比如第三方实现的。
2.有时代理要添加的代码与实现类的功能没有直接联系,不能将那些代码放入实现者内部,会破化一种对象应该只实现一个概念。
3.实现者所展现出来的特点应该对各种用户做隐藏。
4.你可能想隐藏实现方法的名字给用户,出于一些安全的考虑。这需要代理有一个特殊的面貌,也就是方法名与真正实现者的方法名不同。
5.也许要的功能依赖于对象所在的上下文。例如,如果计算机连接到工厂的机械手臂,不需要网络代码来访问手臂,但是工厂的另一端确实需要这段代码。
6.也许这些功能只是用于在开发阶段。例如,你能使用一个代理来实现程序的跟踪,来记录对象的调用次数。这代码在真正部署时不需要。

7.实现者的位置或许是变化的,就好像企业编程。对象进行实际的操作在企业级网络中,经常更换位置取决于负载平衡和故障转移。你可能需要一个智能的代理定位该对象来提供服务给其他用户。

工厂的应用

获得一个代理,经常通过一个工厂对象获得。使用工厂的原因是因为你不用特别关心哪一种实现者来实现你的功能,只要他们能正确实现就好了。


 

public  class  SomeClassFactory  {
  
public final static SomeClassProxy getProxy( ) {
  SomeClassImpl impl 
= new SomeClassImpl(System.getProperty("user.name"));
    
return new SomeClassProxy(impl);
  }

}

 

public  class  DemoProxyFactory  {
  
public static final void main(final String[] args) {
    SomeClassProxy proxy 
= SomeClassFactory.getProxy( );
    proxy.someMethod( );
    proxy.someOtherMethod(
"Our Proxy works!");
  }

}



代理与接口

 

用户有时并不想知道实现的具体细节,也就是到底是代理还是真正实现者完成的功能。如果像上面的工厂类的实现,用户必须知道什么情况下,使用何种代理,这对于用户的使用提高了难度。需要特殊方法来引用合适的代理,Java的接口就使用用于解决这样的问题。

为了隔离实现代理的细节,你能使用接口来描述功能。


 

public  interface  SomeClass  {
  [
public abstractvoid someMethod( );
  [
public abstractvoid someOtherMethod(final String text);
}

 

public  class  SomeClassImpl  implements  SomeClass  {
  
// same as before
}


 

public  class  SomeClassProxy  implements  SomeClass  {
  
// same as before
}


public  class  SomeClassCountingProxy  implements  SomeClass  {
  
// same as before
}


 

public  class  SomeClassFactory  {
  
public static final SomeClass getSomeClassProxy( ) {
      SomeClassImpl impl 
= new SomeClassImpl(System.getProperty("user.name"));
if (LOGGER.isDebugEnabled( )) {
          
return new SomeClassCountingProxy(impl);      
      }
 else {
          
return new SomeClassProxy(impl);      
      }

  }

}


使用

 

public  class  DemoInterfaceProxy  {
  
public static final void main(final String[] args) {
    SomeClass proxy 
= SomeClassFactory.getSomeClassProxy( );
    proxy.someMethod( );
    proxy.someOtherMethod(
"Our Proxy works!");
  }

}



 

提示

if (proxy instanceof SomeClassCountingProxy) {

静态代理的缺点

 System.out.println(((SomeClassCountingProxy)proxy).getInvocationCount());
}

一个静态代理的实例代码:

 

public  class  SomeClassCountingProxy  {
  
private final SomeClassImpl impl;
  
private int invocationCount = 0;
  
public SomeClassCountingProxy(final SomeClassImpl impl) {
    
this.impl = impl;
  }

  
public int getInvocationCount( ) {
    
return invocationCount;
  }

  
public void someMethod( ) {
    
this.invocationCount++;
    
this.impl.someMethod( );
  }

  
public void someOtherMethod(String text) {
    
this.invocationCount++;
    
this.impl.someOtherMethod(text);
  }

}

 

当给不同的对象,编写相同功能的代理类时,会发现需要做很多相同的工作,产生很多相同的代码。例如,都是对实现对象的调用进行计数,对于不同对象,要有不同的代理,但是实际上,他们的逻辑是一样的。这么多代码不容易维护,一个改了,所有的都要修改,是很可怕的。
动态代理,主要使用反射来实行。

主要工作是实现一个InvocationHandler,他会截住对实现者的调用,进行一些逻辑,这时在将请求发给实现者,一旦实现者返回,invocationhandler也返回结果。


 

public  class  MethodCountingHandler  implements  InvocationHandler  {
  
private final Object impl;
  
private int invocationCount = 0;
  
public MethodCountingHandler(final Object impl) {
    
this.impl = impl;
  }

  
public int getInvocationCount( ) {
    
return invocationCount;
  }

  
public Object invoke(Object proxy, Method meth, Object[] args)
                
throws Throwable {
    
try {
      
this.invocationCount++;
      Object result 
= meth.invoke(impl, args);
      
return result;
    }
 catch (final InvocationTargetException ex) {
      
throw ex.getTargetException( );
    }

  }

}

 

这代理提供着与静态代理相同的功能。然而,他使用反射来完成工作的,当用户执行代理的方法时,invocation handler被替换成实现者来被调用。在其内部增加了invocationCount的值并转发调用给实现者通过调用Method对象的invoke()方法。一旦调用完成,实现将会返回一个value给handler。可以将value返回给调用者。
When writing invocation handlers, be careful of methods that return primitive types. The JDK will wrap primitive types in their corresponding wrapper types to return them from a reflexive invocation. The problem is that your handler can return null, but the actual method being called on the implementation cannot. Therefore, if you try to return null after calling a method that returns a primitive, the proxy class will throw a NullPointerException. This NullPointerException applies to the return value, not to the parameters of the method.

可以在invoke方法中加入复杂的逻辑。

得到一个实现者接口的实现者(这里当然就是那个动态代理对象),通过工厂。


 

public  class  SomeClassFactory  {
  
public static final SomeClass getDynamicSomeClassProxy( ) {
    SomeClassImpl impl 
= new SomeClassImpl(System.getProperty("user.name"));
    InvocationHandler handler 
= new MethodCountingHandler(impl);
    Class[] interfaces 
= new Class[] { SomeClass.class };
    ClassLoader loader 
= SomeClassFactory.class.getClassLoader( );
    SomeClass proxy 
= (SomeClass)Proxy.newProxyInstance(loader, 
                                                        interfaces, 
                                                        handler);
    
return proxy;
  }

}



 

In this version of the factory method, SomeClass is an interface implemented by the actual implementation, named SomeClassImpl. This allows you to tell the Proxy class to generate a new proxy that implements the interface SomeClass and uses the invocation handler.
 
One limitation of this system is that the implementation class must implement the interfaces used in the proxy. Therefore, if the implementation did not implement the interface in the first place and the source code is out of your control, this paradigm won't work.

 

public class DemoDynamicProxy {
  
public static final void main(final String[] args) {
    SomeClass proxy 
= SomeClassFactory.getDynamicSomeClassProxy( );
    proxy.someMethod( );
    proxy.someOtherMethod(
"Our Proxy works!");
  }
  
}

 

InvocationHandler handler = Proxy.getInvocationHandler(proxy);
if (handler instanceof MethodCountingHandler) {
 System.out.println(((MethodCountingHandler)handler).getInvocationCount( ));
}

===========================================================================================
 某些接口的实现类,我们要做一个代理,来代理对这些实现类对象的方法调用。

 

 

package  com.ljl.proxy;

import  java.lang.reflect.InvocationHandler;
import  java.lang.reflect.Method;
import  java.lang.reflect.Proxy;
import  java.util.List;
import  java.util.Vector;

public  class  VectorProxy  implements  InvocationHandler {

    
private Object proxyobj;
    
public VectorProxy(Object obj) {
        
super();
        
this.proxyobj = obj;
    }


    
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        System.out.println(
"before calling " + method);
        
if(args!=null)
        
{
            
for(int i = 0; i < args.length;i++)
            
{
                System.out.println(args[i]
+" ");
            }

        }

        Object o 
= method.invoke(proxyobj,args);        
        System.out.println(
"after calling " + method);
        
        
return o;
    }

    
    
public static Object factory(Object obj)
    
{
        Class cls 
= obj.getClass();
        
return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new VectorProxy(obj));
    }

    
    
public static void main(String[] args)
    
{
        List v 
= null;
        v 
= (List)factory(new Vector(10));
        v.add(
"ljl");
        v.add(
"hus");
    }


}

 

public class SomeClassImpl {
  private String userName;  
  public SomeClassImpl(final String userName) {
    this.userName = userName;
  }
    
    public void someMethod( ) {
    System.out.println(this.userName);
  }

  public void someOtherMethod(final String text) {
    System.out.println(text);
  }

}


该类的简单代理

 

 

public class SomeClassProxy {
  private final SomeClassImpl impl;
  public SomeClassProxy(final SomeClassImpl impl) {
    this.impl = impl;
  }


  public void someMethod( ) {
    this.impl.someMethod( );
  }

  public void someOtherMethod(String text) {
    this.impl.someOtherMethod(text);
  }

}


使用代理的原因

 

有一些原因,你需要做代理来在你的应用和实现类之间插入一些有用的代码。
1.实现类的源码不能拿到。比如第三方实现的。
2.有时代理要添加的代码与实现类的功能没有直接联系,不能将那些代码放入实现者内部,会破化一种对象应该只实现一个概念。
3.实现者所展现出来的特点应该对各种用户做隐藏。
4.你可能想隐藏实现方法的名字给用户,出于一些安全的考虑。这需要代理有一个特殊的面貌,也就是方法名与真正实现者的方法名不同。
5.也许要的功能依赖于对象所在的上下文。例如,如果计算机连接到工厂的机械手臂,不需要网络代码来访问手臂,但是工厂的另一端确实需要这段代码。
6.也许这些功能只是用于在开发阶段。例如,你能使用一个代理来实现程序的跟踪,来记录对象的调用次数。这代码在真正部署时不需要。

7.实现者的位置或许是变化的,就好像企业编程。对象进行实际的操作在企业级网络中,经常更换位置取决于负载平衡和故障转移。你可能需要一个智能的代理定位该对象来提供服务给其他用户。

工厂的应用

获得一个代理,经常通过一个工厂对象获得。使用工厂的原因是因为你不用特别关心哪一种实现者来实现你的功能,只要他们能正确实现就好了。


 

public class SomeClassFactory {
  public final static SomeClassProxy getProxy( ) {
  SomeClassImpl impl = new SomeClassImpl(System.getProperty("user.name"));
    return new SomeClassProxy(impl);
  }

}

 

public class DemoProxyFactory  {
  public static final void main(final String[] args) {
    SomeClassProxy proxy = SomeClassFactory.getProxy( );
    proxy.someMethod( );
    proxy.someOtherMethod("Our Proxy works!");
  }

}



代理与接口

 

用户有时并不想知道实现的具体细节,也就是到底是代理还是真正实现者完成的功能。如果像上面的工厂类的实现,用户必须知道什么情况下,使用何种代理,这对于用户的使用提高了难度。需要特殊方法来引用合适的代理,Java的接口就使用用于解决这样的问题。

为了隔离实现代理的细节,你能使用接口来描述功能。

 

public interface SomeClass {
  [public abstract] void someMethod( );
  [public abstract] void someOtherMethod(final String text);
}


 

 

public class SomeClassImpl implements SomeClass  {
  // same as before
}


 

public class SomeClassProxy implements SomeClass  {
  // same as before
}


public class SomeClassCountingProxy implements SomeClass  {
  // same as before
}


 

public class SomeClassFactory  {
  public static final SomeClass getSomeClassProxy( ) {
      SomeClassImpl impl = new SomeClassImpl(System.getProperty("user.name"));
if (LOGGER.isDebugEnabled( )) {
          return new SomeClassCountingProxy(impl);      
      }
 else {
          return new SomeClassProxy(impl);      
      }

  }

}


使用

 

public class DemoInterfaceProxy  {
  public static final void main(final String[] args) {
    SomeClass proxy = SomeClassFactory.getSomeClassProxy( );
    proxy.someMethod( );
    proxy.someOtherMethod("Our Proxy works!");
  }

}



 

提示

if (proxy instanceof SomeClassCountingProxy) {

静态代理的缺点

 System.out.println(((SomeClassCountingProxy)proxy).getInvocationCount());
}

一个静态代理的实例代码:

public class SomeClassCountingProxy {
  private final SomeClassImpl impl;
  private int invocationCount = 0;
  public SomeClassCountingProxy(final SomeClassImpl impl) {
    this.impl = impl;
  }

  public int getInvocationCount( ) {
    return invocationCount;
  }

  public void someMethod( ) {
    this.invocationCount++;
    this.impl.someMethod( );
  }

  public void someOtherMethod(String text) {
    this.invocationCount++;
    this.impl.someOtherMethod(text);
  }

}

 

当给不同的对象,编写相同功能的代理类时,会发现需要做很多相同的工作,产生很多相同的代码。例如,都是对实现对象的调用进行计数,对于不同对象,要有不同的代理,但是实际上,他们的逻辑是一样的。这么多代码不容易维护,一个改了,所有的都要修改,是很可怕的。
动态代理,主要使用反射来实行。

主要工作是实现一个InvocationHandler,他会截住对实现者的调用,进行一些逻辑,这时在将请求发给实现者,一旦实现者返回,invocationhandler也返回结果。

 

public class MethodCountingHandler implements InvocationHandler {
  private final Object impl;
  private int invocationCount = 0;
  public MethodCountingHandler(final Object impl) {
    this.impl = impl;
  }

  public int getInvocationCount( ) {
    return invocationCount;
  }

  public Object invoke(Object proxy, Method meth, Object[] args)
                throws Throwable {
    try {
      this.invocationCount++;
      Object result = meth.invoke(impl, args);
      return result;
    }
 catch (final InvocationTargetException ex) {
      throw ex.getTargetException( );
    }

  }

}


 

 

这代理提供着与静态代理相同的功能。然而,他使用反射来完成工作的,当用户执行代理的方法时,invocation handler被替换成实现者来被调用。在其内部增加了invocationCount的值并转发调用给实现者通过调用Method对象的invoke()方法。一旦调用完成,实现将会返回一个value给handler。可以将value返回给调用者。
When writing invocation handlers, be careful of methods that return primitive types. The JDK will wrap primitive types in their corresponding wrapper types to return them from a reflexive invocation. The problem is that your handler can return null, but the actual method being called on the implementation cannot. Therefore, if you try to return null after calling a method that returns a primitive, the proxy class will throw a NullPointerException. This NullPointerException applies to the return value, not to the parameters of the method.

可以在invoke方法中加入复杂的逻辑。

得到一个实现者接口的实现者(这里当然就是那个动态代理对象),通过工厂。


 

public class SomeClassFactory {
  public static final SomeClass getDynamicSomeClassProxy( ) {
    SomeClassImpl impl = new SomeClassImpl(System.getProperty("user.name"));
    InvocationHandler handler = new MethodCountingHandler(impl);
    Class[] interfaces = new Class[] { SomeClass.class };
    ClassLoader loader = SomeClassFactory.class.getClassLoader( );
    SomeClass proxy = (SomeClass)Proxy.newProxyInstance(loader, 
                                                        interfaces, 
                                                        handler);
    return proxy;
  }

}



 

In this version of the factory method, SomeClass is an interface implemented by the actual implementation, named SomeClassImpl. This allows you to tell the Proxy class to generate a new proxy that implements the interface SomeClass and uses the invocation handler.
 
One limitation of this system is that the implementation class must implement the interfaces used in the proxy. Therefore, if the implementation did not implement the interface in the first place and the source code is out of your control, this paradigm won't work.

public class DemoDynamicProxy {
  public static final void main(final String[] args) {
    SomeClass proxy = SomeClassFactory.getDynamicSomeClassProxy( );
    proxy.someMethod( );
    proxy.someOtherMethod("Our Proxy works!");
  }
  
}

 

InvocationHandler handler = Proxy.getInvocationHandler(proxy);
if (handler instanceof MethodCountingHandler) {
 System.out.println(((MethodCountingHandler)handler).getInvocationCount( ));
}

===========================================================================================
 
package com.ljl.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Vector;

public class VectorProxy implements InvocationHandler{

    private Object proxyobj;
    public VectorProxy(Object obj) {
        super();
        this.proxyobj = obj;
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        System.out.println("before calling " + method);
        if(args!=null)
        {
            for(int i = 0; i < args.length;i++)
            {
                System.out.println(args[i]+" ");
            }

        }

        Object o = method.invoke(proxyobj,args);        
        System.out.println("after calling " + method);
        
        return o;
    }

    
    public static Object factory(Object obj)
    {
        Class cls = obj.getClass();
        return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new VectorProxy(obj));
    }

    
    public static void main(String[] args)
    {
        List v = null;
        v = (List)factory(new Vector(10));
        v.add("ljl");
        v.add("hus");
    }


}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值