代理-静态代理和动态代理
静态代理
1、接口类
1 public interface Star { 2 public void sing(); 3 }
2、被代理类
1 public class Liyuchun implements Star { 2 public void sing() { 3 System.out.println("春哥唱歌"); 4 } 5 }
3、代理类
1 public class LiyuchunProxy implements Star { 2 private Liyuchun liyuchun = new Liyuchun(); 3 public void sing() { 4 liyuchun.sing(); 5 } 6 //基于接口编程 7 public Star getProxy() { 8 return liyuchun; 9 } 10 }
4、用户
1 //哥/歌迷 2 public class Fans { 3 public static void main(String[] args) { 4 //创建代理对象 5 LiyuchunProxy liyuchunProxy = new LiyuchunProxy(); 6 //通过代理对象找目标对象 7 Star star = liyuchunProxy.getProxy(); 8 //业务方法 9 star.sing(); 10 } 11 }
动态代理
动态代理(代理类产生代理对象)
明确两个概念:
•代理对象存在的价值:主要用于拦截对真实业务对象的访问。
•代理对象有什么方法?与真实对象相同,只是无业务代码。
现在要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类,即代理类的对象。
如何编写生成代理对象的类,两个要素:
•代理谁
•如何生成代理对象
代理谁?
•设计一个类变量,以及一个构造函数,记住代理类代理哪个对象。
如何生成代理对象?(invoke方法)
•设计一个方法生成代理对象(在方法内编写代码生成代理对象是此处编程的难点)
Java提供了一个Proxy类,调用它的newInstance()方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:
•1.生成代理对象使用哪个类加载器ClassLoader
•2.生成哪个对象的代理对象,通过接口指定
•3.生成的代理对象的方法里干什么事,由开发人员编写handler接口的实现来指定。
初学者必须记住的2件事情:
•Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
•由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。
开发步骤:
1)写一个普通类,无需任何继承或实现
2)写一个实例变量,记住代理谁,即目标对象
3)使用构造方法为实例变量赋值
4)写一个普通方法,该方法的返回值是接口,该接口是目标对象的实现接口
1、接口类
1 public interface Star { 2 3 public void sing(); 4 public void sing(String money); 5 }
2、被代理类
1 // 目标对象 2 public class Liyuchun implements Star { 3 public void sing() { 4 System.out.println("春哥唱歌"); 5 } 6 public void sing(String money){ 7 System.out.println("春哥的"+money+"万出场费,春哥开始唱歌了"); 8 } 9 }
3、代理类
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 // 代理类 6 public class LiyuchunProxy { 7 8 // 代理谁,通过构造方法赋值 9 private static Liyuchun liyuchun = new Liyuchun(); 10 11 // 基于接口编程,动态产生代理对象 12 /* 13 * 参数一:loader表示动态代理对象是由哪个类加载器完成的 14 参数二:interfaces表示动态代理对象与目标对象(春哥)有一样的方法,即相当于获取目标对象(即被代理类)的方法 15 参数三:表示动态代理对象的栏截方法,即每次调用目标对象都会执行该invoke()方法(难点) 16 17 */ 18 public Star getProxy() { 19 20 ClassLoader classLoader = LiyuchunProxy.class.getClassLoader(); 21 @SuppressWarnings("unchecked") 22 Class<Liyuchun>[] interfaces = (Class<Liyuchun>[]) liyuchun.getClass().getInterfaces(); 23 24 return (Star) Proxy.newProxyInstance( 25 classLoader, //参数一 26 interfaces , //参数二 27 new InvocationHandler() { //参数三 28 29 public Object invoke( 30 Object proxy, 31 Method method, //代理类的方法 32 Object[] args//代理类的参数,第一个参数为args[0],第二个为args[1],以此类推 33 )throws Throwable 34 { 35 /*System.out.println("方法名:"+method.getName());*/ 36 //System.out.println(method); 37 if("sing".equals(method.getName())){ 38 // 调用春哥sing方法 39 String money = (String) args[0]; 40 if(Integer.parseInt(money)>=3){ 41 method.invoke(liyuchun, money); 42 }else{ 43 System.out.println("春哥的出场费不够"); 44 } 45 } 46 return null; 47 } 48 }); 49 } 50 }
4、用户
1 // 歌迷类 2 public class Fans { 3 4 public static void main(String[] args) { 5 // 创建代理对象 6 LiyuchunProxy liyuchunProxy = new LiyuchunProxy(); 7 // 通过代理对象找目标对象 8 Star star = liyuchunProxy.getProxy(); 9 // 业务方法 10 //star.sing(); 11 star.sing("3"); 12 } 13 }
by hacket