需要一个接口(假设这里是 Helloable),内部有某目标方法 void sayHello() ;
真实对象类需要实现该接口,并覆盖目标方法(假设这个真实对象类是HelloImpl)。
代理类要做的事情(代理类 不一定要实现上述接口):
1、持有一个上述接口的引用作为属性,初值为null,将来代表真实对象。
2、代理类中需要自定义一个bind方法
例如bind方法示意: Helloable bind(HelloImpl target) {
this.target = target; //左边是接口的引用,右边是真实对象的引用
return Proxy.newProxyInstance(参数1,参数2,参数3);
}
输入是一个真实对象,输出是上层接口的引用,该引用要代表这个输入的真实对象。代理类并不实现上层接口,与上层接口没有关系,就靠这个bind方法中创建真实对象,赋值给上层接口的引用,并返回该引用,将来在测试类中,用来调用其代表的真实对象中的方法。
在方法中调用 java.lang.reflect.Proxy 类的 Proxy.newProxyInstance( 参数1,参数2,参数3 );方法来得到真实对象。
tatic Object |
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 |
参数1: 真实对象的类加载器,例如 target.getClass().getClassLoader()
参数2: 真实对象实现了哪些接口,例如 target.getClass().getInterfaces() ,该方法的返回值是一个Class<?>[ ]的数组类型;则表达式 target.getClass().getInterfaces()[0]就是接口Helloable对应的Class对象。
参数3: 一般是this,这个this因为一般在代理类的成员方法中,所以就是代指代理类的对象本身。
这个 Proxy.newProxyInstance方法的意思整体就是:使用参数3的代理类对象,去建立一个参数1和2描述的真实的对象。
注意 Proxy.newProxyInstance方法的返回值,就是真实类的对象。
3、最后,代理类需要实现 InvocationHandler接口,并覆盖其中的invoke(参数1,参数2,参数3)方法;(注意,该方法并不会在代码中显式地调用,而是在上述bind过程中自动被调用。)
参数1:用上面Proxy.newProxyInstance方法产生的真实对象,注意,参数1并不显式地出现在方法体内;(见下面的例子)
参数2:要调用的目标方法名
参数3:目标方法中的参数,一般是 Object[ ] args
注意,在该invoke方法的方法体中,需要使用反射的方式去调用真实对象的方法,例如在代理类中覆盖的方法:
@Override
public Object invoke(Helloable proxy , Method method ,Object[ ] args ) throws Throwable{ //覆盖该方法是因为代理类必须实现InvocationHandler接口
System.out.println("进入代理");
System.out.println("调度真实对象方法 前 的服务");
method.invoke(target , args); //J2EE的反射方式调用
System.out.println("调度真实对象方法 后 的服务");
}
见下面的例子:
// 动态代理.Helloable.java
package 动态代理;
public interface Helloable {
public void sayHello();
}
//HelloImpl.java
package 动态代理;
public class HelloImpl implements Helloable {
@Override
public void sayHello() {
System.out.println("真实对象的sayHello()执行");
}
}
//JdkProxy.java
package 动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler{//代理中介类
private Helloable target = null;
public Helloable bind(HelloImpl target) { // 传入真实对象,得到上层接口的引用
this.target = target;
return (Helloable) Proxy.newProxyInstance( target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this );
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理");
System.out.println("调度真实对象方法 前 的服务");
method.invoke(target , args); //J2EE的反射方式调用
System.out.println("调度真实对象方法 后 的服务");
return null;
}
}
//Test.java
package 动态代理;
public class Test {
public static void main(String[] args) {
JdkProxy jdkproxy = new JdkProxy();
Helloable x = jdkproxy.bind(new HelloImpl());
x.sayHello();
}
}
/*输出:
进入代理
调度真实对象方法 前 的服务
真实对象的sayHello()执行
调度真实对象方法 后 的服务
*/
附录:数组赋初值的语法,大括号内,每多一个逗号,数组的元素个数就多一个
String[] s = new String[] {"a", "b", "c"}; // { }是数组赋值
for(int i=0;i<s.length;i++)
System.out.println(s[i]);
/*输出
a
b
c
*/