JAVA代理機制

EJB的攔截用的就是JAVA的代理機制。說廣一點,EJB的實現就是利用代理實現的遠程方法調用。EJB會在伺服器端生成一個實現了所有的接口的類的代理,然後在裡面監聽你所做的所有事情,並與之反應,這樣就實現了遠程調用的效果,你在這邊調用,而EJB容器在別的地方也可以知道你調用了什麼,並返回與之對應的結果,這一切都是用代理來實現的。

下面我們就來認識一下,代理的主要類:java.lang.reflect.Proxy
它定義了一套靜態方法,供我們使用,其中一個最常用的方法就是生成代理對象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
它根據你傳入的類載入器和這個代理將會實現的接口,以及一個調用處理器,來生成一個代理對象.說起來比較抽象,還是給點例子吧:
先聲明一個接口,用來調用代理的方法
/*
* MyInterface.java
*
* Created on 2007年9月8日, 下午4:38
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package test4;
/**
*
* @author hadeslee
*/
public interface MyInterface {
public void sayHello(String s);
public void doSth();
}
然後再寫一個類實現此方法
/*
* Test1.java
*
* Created on 2007年9月8日, 下午4:31
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package test4;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author hadeslee
*/
public class Test1 implements MyInterface{
/** Creates a new instance of Test1 */
public Test1() {
}
public static void main(String[] args) throws Exception{
Test1 list=new Test1();
MyInterface my=(MyInterface)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
list.getClass().getInterfaces(),
new MyHandler<MyInterface>(list));
System.out.println("my.name="+my.getClass().getName());
my.doSth();
my.sayHello("千里冰封");
}
//接口中的方法
public void sayHello(String s) {
System.out.println("sayHello to:"+s);
}
//接口中的方法
public void doSth() {
System.out.println("doSth()");
}
//一個靜態內部類,實現了InvocationHandler的接口,
//它也是一個關鍵的接口,所有代理後的行為都是在這裡實現的
static class MyHandler<T> implements InvocationHandler{
private T t;
public MyHandler(T t){
this.t=t;
}
//實現方法調用
//可以自己加上自己的一些調用,此例中只是在加上了一個輸出
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我知道馬上要被調用的方法是:"+method.getName());
return method.invoke(t,args);
}
}
}
運行上面的類輸出是:
my.name=$Proxy0
我知道馬上要被調用的方法是:doSth
doSth()
我知道馬上要被調用的方法是:sayHello
sayHello to:千里冰封
從這裡可以看出,代理的類的名字換成了$Proxy0,其中$Proxy是所有代理類的類名前綴.我們在調用doSth()和sayHello()的時候,都調用到了我們在代理中設定的輸出.如果你想在這裡代理別的類,也是可以的,只要你符合以上的調用規律.
最後特別要注意的一點是:
//實現方法調用
//可以自己加上自己的一些調用,此例中只是在加上了一個輸出
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我知道馬上要被調用的方法是:"+method.getName());
return method.invoke(t,args);
}
在上面的實現中,千萬不能調用method.invoke(proxy,args).因為proxy本身就是一個代理的對象,你如果再在它上面調用一個方法的話,會無限遞歸的調用這個方法,所以,在InvocationHandler的實現裡面,最好是傳一個代理對象的真正實現進去,這樣就可以還原本來的調用結果,並加上自己的東西在裡面.

相關詞條

熱門詞條

聯絡我們