时间:2017年08月28日星期一
说明:本文部份内容均来自慕课网。@慕课网:http://www.imooc.com
教学源码:https://github.com/zccodere/s...
学习源码:https://github.com/zccodere/s...java
学习本课程基础node
面向对象的设计思惟 了解多态的概念 了解反射机制
课程目标git
代理模式基本概念及分类 了解代理模式开发中应用场景 掌握代理模式实现方式 理解JDK动态代理实现
代理模式定义github
为其余对象提供一种代理以控制对这个对象的访问 代理对象起到中介做用,可去掉功能服务或增长额外的服务
常见的几种代理模式apache
远程代理:相似于客户端服务器这种模式,列一个为不一样地理对象提供局域网表明对象 虚拟代理:根据须要将资源消耗很大的对象进行延迟,真正须要的时候进行建立 保护代理:控制对象的访问权限 智能代理:提供对目标对象额外的服务
代理模式示意图数组
智能引用代理服务器
静态代理 动态代理
静态代理定义dom
代理和被代理对象在代理以前是肯定的。他们都实现相同的接口或者继承相同的抽象类
静态代理类图编辑器
代码编写ide
1.编写Moveable接口
package com.myimooc.designpattern.c3proxy.car; /** * @describe 可行驶的接口 * @author zc * @version 1.0 2017-08-28 */ public interface Moveable { /** * 行驶的方法 */ void move(); }
2.编写Car类
package com.myimooc.designpattern.c3proxy.car; import java.util.Random; /** * @describe 一辆车实现可行驶的接口 * @author zc * @version 1.0 2017-08-28 */ public class Car implements Moveable { @Override public void move() { // 记录汽车行驶的时间 // long starttime = System.currentTimeMillis(); // System.out.println("汽车开始行驶..."); // 实现开车 try { System.out.println("汽车行驶中..."); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // long endtime = System.currentTimeMillis(); // System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } }
3.编写Car2类
package com.myimooc.designpattern.c3proxy.car; /** * @describe 继承的方式实现静态代理 * @author zc * @version 1.0 2017-08-28 */ public class 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) + "毫秒"); } }
4.编写Car3类
package com.myimooc.designpattern.c3proxy.car; /** * @describe 聚合的方式实现静态代理 * @author zc * @version 1.0 2017-08-28 */ public class Car3 implements Moveable { public Car3(Car car) { super(); this.car = car; } private Car car; @Override public void move() { long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); car.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } }
5.编写Client类
package com.myimooc.designpattern.c3proxy.car; /** * @describe 测试类 * @author zc * @version 1.0 2017-08-28 */ public class Client { public static void main(String[] args) { // test1(); test2(); } // 2-2 聚合与继承 代理功能叠加测试方法 public static void test2(){ Car car = new Car(); CarLogProxy clp = new CarLogProxy(car); CarTimeProxy ctp = new CarTimeProxy(clp); ctp.move(); } // 2-1 静态代理测试方法 public static void test1(){ // Car car = new Car(); // car.move(); // 使用继承的方式 // Moveable m = new Car2(); // m.move(); // 使用聚合方式 Car car = new Car(); Moveable m = new Car3(car); m.move(); } }
场景分析
代理类功能叠加
1.记录日志 2.记录时间 3.权限功能
使用继承方式
使用继承方式来实现代理功能的叠加,代理类会无限的膨胀下去,因此这种方式不推荐使用。
使用聚合方式,经过代码演示
代码编写
1.复制Car3命名为CarTimeProxy
package com.myimooc.designpattern.c3proxy.car; /** * @describe 汽车行驶时间的代理 * @author zc * @version 1.0 2017-08-28 */ public class CarTimeProxy implements Moveable { // 由于代理类和被代理类都是实现相同的接口,因此构造方法传递的对象也能够是Moveable对象 public CarTimeProxy(Moveable m) { super(); this.m = m; } private Moveable m; @Override public void move() { long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); m.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } }
2.编写CarLogProxy类
package com.myimooc.designpattern.c3proxy.car; /** * @describe 汽车日志功能的代理 * @author zc * @version 1.0 2017-08-28 */ public class CarLogProxy implements Moveable { // 由于代理类和被代理类都是实现相同的接口,因此构造方法传递的对象也能够是Moveable对象 public CarLogProxy(Moveable m) { super(); this.m = m; } private Moveable m; @Override public void move() { System.out.println("日志开始"); m.move(); System.out.println("日志结束"); } }
3.编写Client类
package com.myimooc.designpattern.c3proxy.car; /** * @describe 测试类 * @author zc * @version 1.0 2017-08-28 */ public class Client { public static void main(String[] args) { // test1(); test2(); } // 2-2 聚合与继承 代理功能叠加测试方法 public static void test2(){ Car car = new Car(); CarLogProxy clp = new CarLogProxy(car); CarTimeProxy ctp = new CarTimeProxy(clp); ctp.move(); } // 2-1 静态代理测试方法 public static void test1(){ // Car car = new Car(); // car.move(); // 使用继承的方式 // Moveable m = new Car2(); // m.move(); // 使用聚合方式 Car car = new Car(); Moveable m = new Car3(car); m.move(); } }
场景分析
有没有方法动态产生代理,实现对不一样类,不一样方法的代理呢
JDK动态代理类图
Java动态代理类位于java.lang.reflect包下,通常主要涉及到如下两个类
Interface InvocationHandler:该接口中仅定义了一个方法 public Object invoke(Object obj,Method method,Object[] args) 在实际使用时,第一参数obj通常是指代理类,method是被代理的方法,args为该方法的参数数组。 这个抽象方法在代理类中动态实现。 Proxy:该类即为动态代理类 static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 返回代理类的一个实例,返回后的代理类能够当作被代理类使用 (可以使用被代理类的在接口中声明过的方法)
所谓Dynamic Proxy是这样一种class
它是在运行时生成的class 该class须要实现一组interface 使用动态代理类时,必须实现InvocationHandler接口
动态代理实现步骤
1.建立一个实现InvocationHandler接口的类,它必须实现invoke方法 2.建立被代理的类以及接口 3.调用Proxy的静态方法,建立一个代理类 newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 4.经过代理调用方法
代码编写
1.编写TimeHandler类
package com.myimooc.designpattern.c3proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @describe 对时间上的处理-使用JDK动态代理 * @author zc * @version 1.0 2017-08-28 */ public class TimeHandler implements InvocationHandler { public TimeHandler(Object target) { super(); this.target = target; } private Object target; /** * 参数: * proxy 被代理对象 * method 被代理对象方法 * args 方法的参数 * 返回值: * Object 方法的返回值 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); method.invoke(target); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); return null; } }
2.编写Test类
package com.myimooc.designpattern.c3proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import com.myimooc.designpattern.c3proxy.car.Car; import com.myimooc.designpattern.c3proxy.car.Moveable; /** * @describe JDK动态代理测试类 * @author zc * @version 1.0 2017-08-28 */ public class Test { public static void main(String[] args) { Car car = new Car(); InvocationHandler h = new TimeHandler(car); Class<?> cls = car.getClass(); // 使用Proxy类newProxyInstance方法动态建立代理类 /** * loader 类加载器 * interfaces 实现接口 * h InvocationHandler */ Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); m.move(); } }
JDK动态代理与CGLIB动态代理区别
JDK动态代理 1.只能代理实现了接口的类 2.没有实现接口的类不能实现JDK的动态代理 CGLIB动态代理 1.针对类来实现代理的 2.对指定目标类产生一个子类,经过方法拦截技术拦截全部父类方法的调用 3.由于是使用继承的方式,因此不能对final修饰的类来进行代理
代码编写
1.添加相关依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep --> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>3.2.5</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
2.编写CglibProxy类
package com.myimooc.designpattern.c3proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * @describe 代理类 * @author zc * @version 1.0 2017-08-28 */ public class CglibProxy implements MethodInterceptor { private Enhancer enhance = new Enhancer(); @SuppressWarnings("rawtypes") public Object getProxy(Class clazz){ // 设置建立子类的类 enhance.setSuperclass(clazz); enhance.setCallback(this); return enhance.create(); } /** * 拦截全部目标类方法的调用 * 参数: * obj 目标类的实例 * method 目标方法的反射对象 * args 方法的参数 * proxy 代理类的实例 */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("日志开始..."); // 代理类调用父类的方法 proxy.invokeSuper(obj, args); System.out.println("日志结束..."); return null; } }
3.编写Train类
package com.myimooc.designpattern.c3proxy.cglib; /** * @describe 火车 * @author zc * @version 1.0 2017-08-28 */ public class Train { public void move(){ System.out.println("火车行驶中"); } }
4.编写Client类
package com.myimooc.designpattern.c3proxy.cglib; /** * @describe cglib代理测试类 * @author zc * @version 1.0 2017-08-28 */ public class Client { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Train t = (Train)proxy.getProxy(Train.class); t.move(); } }
动态代理实现思路
实现功能:经过Proxy的newProxyInstance返回代理对象 1.声明一段源码(动态产生代理) 2.编译编码(JDK Compiler API),产生新的类(代理类) 3.将这个类load到内存当中,产生一个新的对象(代理对象) 4.return 代理对象
代码编写
1.编写InvocationHandler类
package com.myimooc.designpattern.c3proxy.simulationjdk; import java.lang.reflect.Method; /** * @describe 模拟JDK动态代理-业务处理类 * @author zc * @version 1.0 2017-08-28 */ public interface InvocationHandler { public void invoke(Object obj,Method method); }
2.编写Proxy类
package com.myimooc.designpattern.c3proxy.simulationjdk; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import org.apache.commons.io.FileUtils; /** * @describe 模拟JDK动态代理-代理类 * @author zc * @version 1.0 2017-08-28 */ @SuppressWarnings({"rawtypes","unchecked"}) public class Proxy { public static Object newProxyInstance( Class infce,InvocationHandler h)throws Exception{ String rt = "\r\n"; String methodStr = ""; for(Method m : infce.getMethods()){ methodStr += " @Override" + rt + " public void "+ m.getName() +"(){" + rt + " try{" + rt + " Method md = " +infce.getName()+".class.getMethod(\""+m.getName()+"\");" + rt + " h.invoke(this,md);" + rt + " }catch(Exception e){e.printStackTrace();}" + rt + " }" + rt; } String str = "package com.myimooc.designpattern.c3proxy.simulationjdk; " + rt + "import com.myimooc.designpattern.c3proxy.simulationjdk.InvocationHandler;" + rt + "import java.lang.reflect.Method;" + rt + "public class $Proxy0 implements "+ infce.getName() +" { " + rt + " public $Proxy0(InvocationHandler h) {" + rt + " this.h = h;" + rt + " }" + rt + " private InvocationHandler h;" + rt + methodStr + rt + "}"; // 产生代理类的java文件 String filename = System.getProperty("user.dir") + "/target/classes/com/myimooc/designpattern/c3proxy/simulationjdk/$Proxy0.java"; File file = new File(filename); FileUtils.writeStringToFile(file, str,"UTF-8"); // 编译-拿到编辑器 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 文件管理者 StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); // 获取文件 Iterable units = fileMgr.getJavaFileObjects(filename); // 编译任务 CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, units); // 进行编译 task.call(); fileMgr.close(); // load到内存 ClassLoader cl = ClassLoader.getSystemClassLoader(); Class c = cl.loadClass("com.myimooc.designpattern.c3proxy.simulationjdk.$Proxy0"); Constructor ctr = c.getConstructor(InvocationHandler.class); return ctr.newInstance(h); } }
3.编写TimeHandler类
package com.myimooc.designpattern.c3proxy.simulationjdk; import java.lang.reflect.Method; /** * @describe 模拟JDK动态代理-时间业务逻辑处理 * @author zc * @version 1.0 2017-08-28 */ public class TimeHandler implements InvocationHandler{ private Object target; public TimeHandler(Object target) { super(); this.target = target; } @Override public void invoke(Object obj, Method method) { try { long starttime = System.currentTimeMillis(); System.out.println("汽车开始行驶..."); method.invoke(target); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车行驶时间:"+(endtime - starttime) + "毫秒"); } catch (Exception e) { e.printStackTrace(); } } }
4.编写Client类
package com.myimooc.designpattern.c3proxy.simulationjdk; import com.myimooc.designpattern.c3proxy.car.Car; import com.myimooc.designpattern.c3proxy.car.Moveable; /** * @describe 模拟JDK动态代理-测试类 * @author zc * @version 1.0 2017-08-28 */ 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(); } }
总结
代理模式概念、分类及应用场景 场景代理模式 静态代理(继承、聚合) JDK动态代理实现日志处理功能 模拟JDK动态代理实现
代理模式-动态代理