设计模式五 代理模式
Posted idea-persistence
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式五 代理模式相关的知识,希望对你有一定的参考价值。
0、基本定义
为其他对象提供一种代理以控制对这个对象对访问。
静态代理:代理前,所有对行为都是已知对。 不能扩展
动态代理:代理前,所有的行为都是未知的。
》 jdk:必须实现 interface,从interface中,获取method,进行字节码重组,生成新类。
》 cgli:对类进行代理,Enhance 需要设置 被代理的类作为 superClass,生成被代理类的子类。
1、代码实现(gupao学院的demo)
1.1 静态代理
public class Father { private Son person; //强依赖,不能扩展 public Father(Son person) { this.person = person; } public void findLove() { System.out.println("开始五色"); this.person.findLove(); System.out.println("结束"); } } public class Son { public void findLove() { System.out.println("找对象,大长腿"); } } public class StaticProxyTest { public static void main(String[] args) { Son son = new Son(); Father father = new Father(son); father.findLove(); } }
1.2 动态代理
采用tom老师经典案例,meipo
jdk代理
public interface Person { void findLove(); void job(); } public class XieMu implements Person{ @Override public void findLove() { System.out.println("gaofus"); System.out.println("身高175"); System.out.println("人好"); } @Override public void job() { System.out.println("salary 》 15k"); } } public class JDKMeipo implements InvocationHandler{ private XieMu target; public Object getInstance(XieMu target) { this.target = target; //生成新类 return 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(this.target,args); return null; } } public class JDK58 implements InvocationHandler{ private Person target; public Object getInstance(Person target) { this.target = target; //生成新类 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println( "我是58,开始找工作 "); method.invoke(this.target,args); return null; } } public class JDKProxyTest { public static void main(String[] args) throws IOException { // Person instance = (Person) new JDKMeipo().getInstance(new XieMu()); // instance.findLove(); Person proxy = (Person) new JDK58().getInstance(new XieMu()); proxy.job(); byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class}); FileOutputStream fos = new FileOutputStream("$Proxy.class"); fos.write(bytes); fos.close(); } }
cgli 代理
public class Zhangsan { public void findLove() { System.out.println("人美"); } } public class CglibMeipo implements MethodInterceptor { public Object getInstance(Class clazz) { Enhancer enhancer = new Enhancer(); //设置生成新类的父类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //增强 System.out.println( "我是媒婆,已经拿到需求"); System.out.println( "开始五色"); methodProxy.invokeSuper(o, objects); System.out.println("合适"); return null; } } public class CglibTest { public static void main(String[] args) { Zhangsan instance = (Zhangsan) new CglibMeipo().getInstance(new Zhangsan().getClass()); instance.findLove(); System.out.println(instance.getClass()); } }
1.3 自定义代理
GPClassLoader.java
public class GPClassLoader extends ClassLoader{ private File classPathFile; public GPClassLoader() { String classPath = GPClassLoader.class.getResource("").getPath(); this.classPathFile = new File(classPath); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String className = GPClassLoader.class.getPackage().getName() + "." + name; if (classPathFile != null) { File classFile = new File(classPathFile, name.replaceAll("\.", "/") + ".class"); if (classFile.exists()) { FileInputStream fis = null; ByteArrayOutputStream out = null; try { fis = new FileInputStream(classFile); out = new ByteArrayOutputStream(); byte[] buff = new byte[1024]; int len; while ((len = fis.read(buff)) != -1) { out.write(buff, 0, len); } return defineClass(className, out.toByteArray(), 0, out.size()); } catch (Exception e) { } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } } return super.findClass(name); } }
GPProxy.java
public class GPProxy { public static Object newProxyInstance(GPClassLoader classLoader , Class<?>[] interfaces, GPInvocationHandler handler ) throws Exception { // 1、动态生成源代码 String src = generateSrc(interfaces); //2、java文件 输出到 磁盘 String filePath = GPProxy.class.getResource("").getPath(); System.out.println(filePath); File f = new File(filePath + "$Proxy0.java"); FileWriter fw = new FileWriter(f); fw.write(src); fw.flush(); //3、生成的java文件 编译成 .class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null); Iterable iterable = manage.getJavaFileObjects(f); JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable); task.call(); manage.close(); //4、编译生成的.class文件加载到jvm中 Class proxyClass = classLoader.findClass("$Proxy0"); Constructor c = proxyClass.getConstructor(GPInvocationHandler.class); f.delete(); //5、返回字节码重组后的新的代理对象 return c.newInstance(handler); } public static final String ln = " "; private static String generateSrc(Class<?>[] interfaces) { StringBuffer sb = new StringBuffer(); sb.append("package com.zzf.design.proxy.custom;" + ln); sb.append("import com.zzf.design.proxy.jdk.Person;" + ln); sb.append("import java.lang.reflect.Method;" + ln); sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln); sb.append("GPInvocationHandler h;" + ln); sb.append("public $Proxy0(GPInvocationHandler h) { " + ln); sb.append("this.h = h;"); sb.append("}" + ln); for (Method m : interfaces[0].getMethods()){ sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln); sb.append("try{" + ln); sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod("" + m.getName() + "",new Class[]{});" + ln); sb.append("this.h.invoke(this,m,null);" + ln); sb.append("}catch(Throwable e){" + ln); sb.append("e.printStackTrace();" + ln); sb.append("}"); sb.append("}"); } sb.append("}" + ln); return sb.toString(); } }
InvocationHandler.java
public interface GPInvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
借此机会熟悉了下 ClassLoader ,一些IO流使用。受益很多。在此纪录。
代理过程中 主要就是 字节码重组,生成了一个新类 $Proxy.java 。在平时的调试过程中,是找不到该类的,运行时使用后,就立马删除了。
字节码重组原理 //1、拿到被代理对象的引用,并获取它的所有接口,反射获取 //2、jdk proxy 类重新生成一个新的类,同时新的类要实现被代理类所有实现方法 //3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用 //4、编译新生成的java代码 .class //5、在重新加载到 jvm中运行
2 使用场景
spring AOP 是使用代理很好的一种实现。
==========================================
想学着用语言来进行描述,但还达不到程度,这更像是一份代码笔记。
=========================================
参考资料:
咕泡学院
以上是关于设计模式五 代理模式的主要内容,如果未能解决你的问题,请参考以下文章
深入理解设计模式-代理模式(静态代理动态代理jdk和cglib)
深入理解设计模式-代理模式(静态代理动态代理jdk和cglib)