某些接口的實現(xiàn)類,我們要做一個代理,來代理對這些實現(xiàn)類對象的方法調(diào)用。

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);
}
}

使用代理的原因
有一些原因,你需要做代理來在你的應(yīng)用和實現(xiàn)類之間插入一些有用的代碼。
1.實現(xiàn)類的源碼不能拿到。比如第三方實現(xiàn)的。
2.有時代理要添加的代碼與實現(xiàn)類的功能沒有直接聯(lián)系,不能將那些代碼放入實現(xiàn)者內(nèi)部,會破化一種對象應(yīng)該只實現(xiàn)一個概念。
3.實現(xiàn)者所展現(xiàn)出來的特點應(yīng)該對各種用戶做隱藏。
4.你可能想隱藏實現(xiàn)方法的名字給用戶,出于一些安全的考慮。這需要代理有一個特殊的面貌,也就是方法名與真正實現(xiàn)者的方法名不同。
5.也許要的功能依賴于對象所在的上下文。例如,如果計算機連接到工廠的機械手臂,不需要網(wǎng)絡(luò)代碼來訪問手臂,但是工廠的另一端確實需要這段代碼。
6.也許這些功能只是用于在開發(fā)階段。例如,你能使用一個代理來實現(xiàn)程序的跟蹤,來記錄對象的調(diào)用次數(shù)。這代碼在真正部署時不需要。
7.實現(xiàn)者的位置或許是變化的,就好像企業(yè)編程。對象進行實際的操作在企業(yè)級網(wǎng)絡(luò)中,經(jīng)常更換位置取決于負載平衡和故障轉(zhuǎn)移。你可能需要一個智能的代理定位該對象來提供服務(wù)給其他用戶。
工廠的應(yīng)用
獲得一個代理,經(jīng)常通過一個工廠對象獲得。使用工廠的原因是因為你不用特別關(guān)心哪一種實現(xiàn)者來實現(xiàn)你的功能,只要他們能正確實現(xiàn)就好了。

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!");
}
}

代理與接口
用戶有時并不想知道實現(xiàn)的具體細節(jié),也就是到底是代理還是真正實現(xiàn)者完成的功能。如果像上面的工廠類的實現(xiàn),用戶必須知道什么情況下,使用何種代理,這對于用戶的使用提高了難度。需要特殊方法來引用合適的代理,Java的接口就使用用于解決這樣的問題。
為了隔離實現(xiàn)代理的細節(jié),你能使用接口來描述功能。

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());
}
一個靜態(tài)代理的實例代碼:

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);
}
}

靜態(tài)代理的缺點
當(dāng)給不同的對象,編寫相同功能的代理類時,會發(fā)現(xiàn)需要做很多相同的工作,產(chǎn)生很多相同的代碼。例如,都是對實現(xiàn)對象的調(diào)用進行計數(shù),對于不同對象,要有不同的代理,但是實際上,他們的邏輯是一樣的。這么多代碼不容易維護,一個改了,所有的都要修改,是很可怕的。
動態(tài)代理,主要使用反射來實行。
主要工作是實現(xiàn)一個InvocationHandler,他會截住對實現(xiàn)者的調(diào)用,進行一些邏輯,這時在將請求發(fā)給實現(xiàn)者,一旦實現(xiàn)者返回,invocationhandler也返回結(jié)果。

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( );
}
}
}

這代理提供著與靜態(tài)代理相同的功能。然而,他使用反射來完成工作的,當(dāng)用戶執(zhí)行代理的方法時,invocation handler被替換成實現(xiàn)者來被調(diào)用。在其內(nèi)部增加了invocationCount的值并轉(zhuǎn)發(fā)調(diào)用給實現(xiàn)者通過調(diào)用Method對象的invoke()方法。一旦調(diào)用完成,實現(xiàn)將會返回一個value給handler。可以將value返回給調(diào)用者。
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方法中加入復(fù)雜的邏輯。
得到一個實現(xiàn)者接口的實現(xiàn)者(這里當(dāng)然就是那個動態(tài)代理對象),通過工廠。

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");
}

}

posted on 2006-01-30 18:27
北國狼人的BloG 閱讀(2023)
評論(0) 編輯 收藏