动态代理实现思路
实现功能;通过Proxy的newProxyInstance返回代理对象
1.声明一段源码(动态产生代理)
2.编译源码(JDK Compiler API),产生新的类(代理类)
3.将这个类load到内存当中,产生一个新的对象(代理对象)
4.return 代理对象
设计模式——代理模式(具备面向对象的设计思维、了解多态、反射机制)
一、基本概念及分类
1、定义:为其他对象提供一种代理以控制对这个对象的访问(购买火车票去代售网点、找代理),代理对象起到中介作用,可去掉功能服务或增加额外服务。
2、常见的代理模式
(1)远程代理:为不同地理的对象提供局域网代表对象(客户端、服务器等)
例如:连锁店查看门店经营情况(通过远程代理可以监控各个店铺,使之能直观地了解店内信息)
(2)虚拟代理:格局需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建
例如:浏览网页中的图片时以默认图片显示,当图片加载完成后再查看
(3)智能引用代理:提供给目标对象一些额外的服务
例如:火车票代售处、日志处理、权限管理、事务处理...
(4)保护代理:控制对一个对象的访问权限
例如:浏览网页时,普通用户只有浏览权限,当用户注册登录后,才可以进行发帖、删除、评论等操作
二、开发中的应用场景
三、实现方式(以智能引用代理为例)
1、静态代理:代理和被代理对象在代理之前是确定的,它们都实现相同的接口或者继承相同的抽象类。
实现例子:车辆在公路上行驶,通过代理实现车辆行驶的方法,增加一个记录车辆行驶的方法
不使用代理正常实现:
public interface Moveable{ void move(); } public class Car implements Moveable{ @Override public void move(){ long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); //实现开车 try{ Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中..."); }catch(InterruptedException e){ e.printStackTrace(); } long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } } public class Client{ public static void main(String[] args){ Car car = new Car(); car.move(); } }
(1)通过继承的方式实现:
public interface Moveable{ void move(); } public class Car implements Moveable{ @Override public void move(){ //实现开车 try{ Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中..."); }catch(InterruptedException e){ e.printStackTrace(); } } } public calss Car2 extends Car{ @Override public void move(){ long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); super.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } } public class Client{ public static void main(String[] args){ Moveable m = new Car2(); m.move(); } }
(2)通过聚合(一个类当中调用另一个对象)的方式实现:
public interface Moveable{ void move(); } public class Car implements Moveable{ @Override public void move(){ //实现开车 try{ Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中..."); }catch(InterruptedException e){ e.printStackTrace(); } } } public calss Car3 implements Moveable{ private Car car; public Car3(Car car){ super(); this.car = car; } @Override public void move(){ long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); car.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } } public class Client{ public static void main(String[] args){ Car car = new Car(); Moveable m = new Car3(car); m.move(); } }
思考:通过继承和聚合两种方式都能实现静态代理,但究竟哪种方式更好呢?
以上是在实现对象方法move()的外层添加方法运行时间处理功能,想要增加权限管理、增加日志处理实现功能的叠加,通过两种方式示例:
(1)通过继承方式实现(代理类会无限膨胀下去)
先记录日志,再记录时间:需要先创建类Car4继承Car2或者Car,在move()方法前后先记录日志,再记录时间;
先记录时间,再记录日志:需要先创建类Car5继承Car2或者Car,在move()方法前后先记录时间,再记录日志;
先处理权限,再记录日志,再记录时间:需要先创建类Car6继承Car2或者Car,先处理权限,再记录日志,再记录时间;
先处理权限,再记录时间,再记录日志:需要先创建类Car7继承Car2或者Car,先处理权限,再记录时间,再记录日志;
(2)通过聚合方式实现 (代理类实现相同的接口,且代理之间相互传递、组合)
public interface Moveable{ void move(); } public class Car implements Moveable{ @Override public void move(){ //实现开车 try{ Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中..."); }catch(InterruptedException e){ e.printStackTrace(); } } } public calss CarTimeProxy implements Moveable{ private Moveable m; public CarTimeProxy (Moveable m){ super(); this.m = m; } @Override public void move(){ long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); m.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } } public calss CarLogProxy implements Moveable{ private Moveable m; public CarLogProxy (Moveable m){ super(); this.m = m; } @Override public void move(){ System.out.println("日志开始..."); m.move(); System.out.println("日志结束..."); } } public class Client{ public static void main(String[] args){ Car car = new Car(); //先记录日志,再记录时间 CarTimeProxy ctp = new CarTimeProxy (car); CarLogProxy clp = new CarLogProxy (ctp); clp.move(); //先记录时间,再记录日志 CarLogProxy clp = new CarLogProxy (car); CarTimeProxy ctp = new CarTimeProxy (car); ctp .move(); } }
思考:不同的类(Car,Train)实现相同的代理(TimeProxy,LogProxy)怎样实现(如果用静态代理的聚合方式实现,每增加一个类就要新创建新类的TimeProxy,LogProxy代理类,造成类膨胀)?
有没有一种方法:能够动态产生代理,实现对不同类、不同方法的代理——动态代理
2、动态代理(在代理类与被代理类之间加入了实现InvocationHandler【事务处理器】类)
(一)JDK动态代理
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1)Interface Invocationhandler:该接口中仅定义了一个方法
public Object invoke(Object obj,Method method, Object[] args)
在实际使用中,参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2)Proxy:该类即为动态代理类
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) :返回代理类的一个实例,返回后的代理类可以当做被代理类使用(可使用被代理类的在接口中声明过的方法)
JDK动态代理代码实现:
public interface Moveable{ void move(); } public class Car implements Moveable{ @Override public void move(){ //实现开车 try{ Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中..."); }catch(InterruptedException e){ e.printStackTrace(); } } } public class TimeHandler implements InvocationHandler{ private Object target; public TimeHandler(Object target){ super(); this.target = target; } /* *参数: *proxy:被代理的对象 *method:被代理对象的方法 *args:方法的参数 *返回值: *Object:方法的返回值 */ @Override public Object invoke(Object proxy,Method method,Object[] args) throw Throwable{ long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); method.invoke(target); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } } //JDK动态代理测试 public class Test{ public static void main(String[] args){ Car car = new Car(); InvocationHandler h = new TimeHandler(car); Class<?> cls = car.getClass(); /* *参数: *loader:类加载器 *interfaces:实现接口 *h:实现处理器InvocationHandler */ Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h); m.move(); } }
所谓动态代理是在运行时生成的class,该class需要实现一组interface,使用动态代理类时,必须事先InvocationHandler接口。
JDK动态代理实现步骤:
1、创建一个实现皆苦InvocationHandler的类,它必须事先invoke()方法;
2、创建被代理的类及接口;
3、调用Proxy类的静态方法,创建一个代理类;
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
4、通过代理调用方法。
实现作业:实现Car类的多个动态代理类(记录日志、时间)
实现作业:实现Car类的多个动态代理类(记录日志、时间)
(二)CGLIB动态代理
JDK动态代理与CGLIB动态代理的区别:
JDK动态代理:
1、只能代理实现了接口的类;
2、没有实现接口的类不能实现JDK的动态代理。
CGLIB动态代理:
1、针对类来实现代理的;
2、对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。
CGLIB动态代理实现代码示例(导包:cglib-nodep-2.2.jar):
public class Train{ public void move(){ System.out.println("火车行驶中......") } } public class CglibProxy implements MethodInterceptor{ private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz){ //设置创建子类的类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } /*拦截所有目标类方法的调用 *参数: *obj:目标类的实例 *m:目标方法的反射对象 *args:方法的参数 *proxy:代理类的实例 */ @Override public Object intercept(Object obj, Method m, Object[] args,MethodProxy proxy) throw Throwable{ System.out.println("日志开始..."); //代理类调用父类的方法 proxy.invoke(obj,args); System.out.println("日志结束..."); return null; } } public class Test{ public static void main(String[] args){ CglibProxy proxy = new CglibProxy(); Train t = proxy.getProxy(Train.class); t.move(); } }
四、理解JDK动态代理的实现
动态代理实现思路(实现功能:通过Proxy的newProxyInstance返回代理对象)
1、声明一段源码(动态产生代理)
2、编译源码(JDKCompiler API),产生新的类(代理类)
3、将这个类load到内存当中,产生一个新的对象(代理对象)
4、return代理对象
代码实现:
public class Proxy{ public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{ String rt = "\r\t"; String methodStr = ""; for(Method m : infce.getMethods()){ methodStr +="@Override" + rt + "public void "+m.getName()+"(){" + rt + /* "long starttime = System.currentTimeMillis();" + rt + "System.out.println("汽车开始行驶...");" + rt + "m."+m.getName()+"();" + rt + "long endtime = System.currentTimeMillis();" + rt + "System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒");" + rt + */ "try{" + rt + "Method md =" + infce.getName() +".class.getMethod(\""+m.getName()+"\");" + rt + "h.invoke(this,md);" + rt + "}catch(Exceotipn e){" + rt + "e.printStackTrace();" + rt + "}" + rt + "}"; } String str = "public calss $Proxy0 implements" + infce.getName()+ "{" + rt + "public $Proxy0 (InvocationHandler h){" + rt + "super();" + rt + "this.h = h;" + rt + "}" + rt + " private InvocationHandler h;" + rt + methodStr + rt + "}"; //String filename = System.getProperty("user.dir"); //System.out.println(filename);//C:/Proxy //产生代理类的Java文件 String filename = System.getProperty("user.dir")+"/bin/com/imooc/proxy/$Proxy0.java"; File file = new File(filename); //FileUtils(commons-io的jar包下的类) FileUtils.writeStringToFile(file,str); //编译 //拿到编译器 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); //文件管理者 StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null); //获取文件 Iterable units = fileMgr.getJavaFileObjects(filename); //编译任务 CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,units); //进行编译 t.call(); fileMgr.close(); //load到内存 ClassLoader cl = ClassLoader.getSystemClassLoader(); Class c = cl.loadClass("$Proxy0"); Constructor ctr = c.getConstructor(InvocationHandler.class); System.out.println(c.getName());//$Proxy0 return ctr.newInstance(h); } } /*测试类*/ public class Client{ public static void main(String[] args) throws Exception{ Car car = new Car(); InvocationHandler h = new TimeHandler(car); Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h); m.move(); } } public class Test{ public static void main(String[] args){ Car car = new Car(); InvocationHandler h = new TimeHandler(car); Class<?> cls = car.getClass(); /* *参数: *loader:类加载器 *interfaces:实现接口 *h:实现处理器InvocationHandler */ Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h); System.out.println("代理类名字" + m.getClass().getName());//代理类名字$Proxy0 m.move(); } }
public class InvocationHandler{ public void invoke(Object o,Method m); } public class TimeHandler implements InvocationHandler{ private O bject target; public TimeHandler(Object target){ this.target = target; } @Override public void invoke(Object o,Method m){ try{ long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); m.invoke(target); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); }catch(Exception e){ e.printStackTrace(); } } }
五、总结
2222222222222222222222222222
11111111111111111111111111111111
22222222222222222222222222222222
555555555555555555555555555
333333333333333333333333333333333
3333333333333333333333333333333333
222222222222222222222222222222222222222
实现静态代理的两种方式
静态代理的概念
智能引用代理的两种实现方式
常见代理模式
智能引用代理
保护代理应用
虚拟代理例子
虚拟代理概念
例 子 例 子
远 程 代 理
常用代理模式
代理模式基本概念
代理模式定义
JDK动态代理:
proxy.newProxcyInstance(class.getlClassLoder(),class.getinterface(),h);
他是在运行生成的class
该class需要实现一组interface
使用动态代理类时,必须实现InvaocationHandler接口
实现invocationHandler接口
invoke(Object proxy,Method method,Object[] args)
proxy:被代理对象
method:被代理对象的方法
args:方法的参数
ppt上关于proxy的注释写错了,写成了代理类。
动态代理实现思路 实现功能;通过Proxy的newProxyInstance返回代理对象 1.声明一段源码(动态产生代理) 2.编译源码(JDK Compiler API),产生新的类(代理类) 3.将这个类load到内存当中,产生一个新的对象(代理对象) 4.return 代理对象
测试 cglib
返回代理类
cglib动态代理实现
proxy.invokeSuper(obj,args)
cglib vs jdk
JDK动态代理机制:只能代理实现某些接口的类,如果没有实现接口的类则不能使用JDK动态代理。
cglib动态代理机制:针对类产生代理,原理就是为指定的目标类产生一个子类,子类通过方法拦截技术(覆盖父类的方法来实现功能的增强)拦截所有父类方法的调用(因为该种方式是使用继承方式,所以不能对final修饰的类进行代理)。