JDK动态代理用法总结

需要一个接口(假设这里是 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
*/

猜你喜欢

转载自blog.csdn.net/qq_26882339/article/details/112385881
今日推荐