Java反射及注解学习- 反射的使用 - JDK动态代理
代理模式基本概念:
1.代理模式的作用:为其他对象提供一种以控制对方的访问
在某种情况下,一个客户不想或者不能直接引用另一个对象,代理可以在客户端和目标对象之间起到中介的作用
代理的角色:
(1)抽象角色:声明真实对象和代理对象的共同接口(比如租房,抽象角色就是把租房这件事给抽象成一个接口)
(2)代理角色:代理对象内部含有真实对象的引用,从而可以操纵真实的对象,同时代理对象提供与真实对象相同的接口,以便在任何时候都能代替真实对象。代理对象可以在执行真实对象操作时附加其他的操作(比如,租房时,中介收中介费),相对于真实对象进行封装。
(3)真实角色:代理对象所代理的真实角色,是我们要引用的对象
2.JDK动态代理
JDK动态代理可以为所有接口的实现类提供代理
动态代理开发步骤:
(1)创建一个实现接口InvocationHandler的类,它必须实现invoke方法
(2)创建被代理对象的类和接口
(3)通过Proxy.newProxyInstance()来创建代理类
(4)通过代理来调用被代理对象的方法
静态代理demo:模拟通过代理租房
1 package proxydemo; 2 3 public interface HireHouse { 4 5 public void hire(); 6 }
1 package proxydemo; 2 3 public class HireHouseImpl implements HireHouse { 4 5 @Override 6 public void hire() { 7 System.out.println("我要租房"); 8 9 } 10 11 }
代理类,实现HireHouse接口,持有代理对象(真实对象的引用)
1 package proxydemo; 2 3 public class HireHouseProxy implements HireHouse { 4 5 private HireHouse hh;//代理对象,持有真实对象的引用 6 7 8 public HireHouseProxy(HireHouse hh) { 9 /*多态方式,接收接口的实现类对象,为静态代理,缺点是,只能给租房这件事做代理, 10 *因为传递进来的是HireHouse这个接口的实现类对象 ,不能代理其他的事情*/ 11 super(); 12 this.hh = hh; 13 } 14 15 16 @Override 17 public void hire() { 18 System.out.println("收中介费");//代理做的事情 19 hh.hire();//真实对象租房 20 System.out.println("扣押金");//代理做的 21 22 } 23 24 }
调用代理类:
1 package proxydemo; 2 3 public class Client { 4 5 public static void main(String[] args) { 6 HireHouse proxyHire = new HireHouseProxy(new HireHouseImpl()); 7 System.out.print("---通过代理租房:"); 8 proxyHire.hire();//通过代理租房 9 System.out.print("---真实对象自己租房:"); 10 new HireHouseImpl().hire();//真实对象自己租房 11 12 } 13 }
动态代理demo:
1 package proxydemo.dynamic.proxy; 2 /** 3 * 真实对象和代理对象的共同接口,不仅仅能租房。 4 * @author Administrator 5 * 6 */ 7 public interface HireHouse { 8 9 public void hire(); 10 }
接口实现类:
1 package proxydemo.dynamic.proxy; 2 3 public class HireHouseImpl implements HireHouse { 4 5 @Override 6 public void hire() { 7 System.out.println("我要租房"); 8 } 9 }
代理类,实现InvocationHandler 接口
1 package proxydemo.dynamic.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 /** 7 * 实现InvocationHandler接口,通过反射去调用被代理的接口 8 * @author Administrator 9 * 10 */ 11 public class HireProxy implements InvocationHandler { 12 // 被代理的真实角色 13 private Object obj;// 真实角色,要给任何对象做代理,只能是持有Object类型的对象 14 15 public HireProxy(Object obj) { 16 super(); 17 this.obj = obj; 18 } 19 20 /** 21 * jdk动态代理,被代理对象必须实现接口 22 * 被代理的对象必然实现共同的Hire接口,那么就有方法 23 * method:被代理的对象的接口中的方法,要调用方法,必须有对象,此处这个对象就是被代理对象,因此必须要指定被代理的对象 24 * args是被代理对象接口的方法的参数,调用proxy对象的method方法 25 */ 26 @Override 27 public Object invoke(Object proxy, Method method, Object[] args) 28 throws Throwable { 29 System.out.println("前置工作"); 30 // for (Object object : args) { 31 // System.out.print("invoke方法中的第三个参数:"+object +" ");//给list做代理时测试用 32 // } 33 Object invoke = method.invoke(obj, args); 34 System.out.println("\n后置工作"); 35 return invoke; 36 } 37 38 }
动态代理测试:
1 package proxydemo.dynamic.proxy; 2 3 import java.lang.reflect.Proxy; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 public class Client { 8 9 public static void main(String[] args) { 10 // 创建被代理的接口实现类对象 11 HireHouseImpl hhi = new HireHouseImpl(); 12 //创建代理对象:第一个参数是被代理的对象的类加载器,第二个是被代理对象的类的所有接口,第三个参数是自定义代理类的角色 13 HireHouse hh = 14 (HireHouse)Proxy.newProxyInstance(hhi.getClass().getClassLoader(), 15 hhi.getClass().getInterfaces(), new HireProxy(hhi)); 16 hh.hire(); 17 18 // 给list做代理 19 // List list = new ArrayList(); 20 // List hh1 = (List) Proxy.newProxyInstance(list.getClass() 21 // .getClassLoader(), list.getClass().getInterfaces(), 22 // new HireProxy(list)); 23 // hh1.add("张三"); 24 // hh1.get(0);//被代理对象的所有方法都被代理了 25 26 } 27 }