EJB會在服務(wù)器端生成一個實現(xiàn)了所有的接口的類的代理,然后在里面監(jiān)聽你所做的所有事情,并與之反應(yīng),這樣就實現(xiàn)了遠程調(diào)用的效果,你在這邊調(diào)用,而EJB容器在別的地方也可以知道你調(diào)用了什么,并返回與之對應(yīng)的結(jié)果,這一切都是用代理來實現(xiàn)的.
下面我們就來認識一下,代理的主要類:java.lang.reflect.Proxy
它定義了一套靜態(tài)方法,供我們使用,其中一個最常用的方法就是生成代理對象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
它根據(jù)你傳入的類加載器和這個代理將會實現(xiàn)的接口,以及一個調(diào)用處理器,來生成一個代理對象.說起來比較抽象,還是給點例子吧:
先聲明一個接口,用來調(diào)用代理的方法
/*
* 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();
}
* 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();
}
然后再寫一個類實現(xiàn)此方法
/*
* 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()");
}
//一個靜態(tài)內(nèi)部類,實現(xiàn)了InvocationHandler的接口,
//它也是一個關(guān)鍵的接口,所有代理后的行為都是在這里實現(xiàn)的
static class MyHandler<T> implements InvocationHandler{
private T t;
public MyHandler(T t){
this.t=t;
}
//實現(xiàn)方法調(diào)用
//可以自己加上自己的一些調(diào)用,此例中只是在加上了一個輸出
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我知道馬上要被調(diào)用的方法是:"+method.getName());
return method.invoke(t,args);
}
}
}
* 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()");
}
//一個靜態(tài)內(nèi)部類,實現(xiàn)了InvocationHandler的接口,
//它也是一個關(guān)鍵的接口,所有代理后的行為都是在這里實現(xiàn)的
static class MyHandler<T> implements InvocationHandler{
private T t;
public MyHandler(T t){
this.t=t;
}
//實現(xiàn)方法調(diào)用
//可以自己加上自己的一些調(diào)用,此例中只是在加上了一個輸出
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我知道馬上要被調(diào)用的方法是:"+method.getName());
return method.invoke(t,args);
}
}
}
運行上面的類輸出是:
my.name=$Proxy0
我知道馬上要被調(diào)用的方法是:doSth
doSth()
我知道馬上要被調(diào)用的方法是:sayHello
sayHello to:千里冰封
從這里可以看出,代理的類的名字換成了$Proxy0,其中$Proxy是所有代理類的類名前綴
我們在調(diào)用doSth()和sayHello()的時候,都調(diào)用到了我們在代理中設(shè)置的輸出.如果你想在這里代理別的類,也是可以的,只要你符合以上的調(diào)用規(guī)律.
最后特別要注意的一點是:
//實現(xiàn)方法調(diào)用
//可以自己加上自己的一些調(diào)用,此例中只是在加上了一個輸出
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我知道馬上要被調(diào)用的方法是:"+method.getName());
return method.invoke(t,args);
}
//可以自己加上自己的一些調(diào)用,此例中只是在加上了一個輸出
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我知道馬上要被調(diào)用的方法是:"+method.getName());
return method.invoke(t,args);
}
在上面的實現(xiàn)中,千萬不能調(diào)用method.invoke(proxy,args).因為proxy本身就是一個代理的對象,你如果再在它上面調(diào)用一個方法的話,會無限遞歸的調(diào)用這個方法,所以,在InvocationHandler的實現(xiàn)里面,最好是傳一個代理對象的真正實現(xiàn)進去,這樣就可以還原本來的調(diào)用結(jié)果,并加上自己的東西在里面.
盡管千里冰封
依然擁有晴空
你我共同品味JAVA的濃香.