Java设计模式之代理模式
现以一个小姑娘寻找对象的例子来说明java中静态代理,JDK动态代理和CGLIB动态代理的使用和原理。
假设存在两种角色,小姑娘和媒婆。其中小姑娘需要寻找对象,她会将需求告诉媒婆,媒婆作为中介,会帮助小姑娘寻找对象。下面以java代码来说明这个过程。
以下是java静态代理的实现过程:
public interface Person { int findLove(); }
public class Girl implements Person { @Override public int findLove() { System.out.println("高富帅"); System.out.println("身高180cm"); System.out.println("有6块腹肌"); return 0; } }
public class MeiPo implements Person { private Girl target; public MeiPo(Girl target){ this.target = target; } @Override public int findLove() { before(); this.target.findLove(); after(); return 0; } private void before(){ System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求"); System.out.println("开始物色"); } private void after(){ System.out.println("OK的话,准备办事"); } }
public class App { public static void main(String[] args) { Girl girl = new Girl(); MeiPo meiPo = new MeiPo(girl); meiPo.findLove(); } }
以下是jdk动态代理的实现过程:
public interface IPerson { int findLove(); }
public class Girl implements IPerson{ @Override public int findLove() { System.out.println("高富帅"); System.out.println("身高180cm"); System.out.println("有6块腹肌"); return 0; } }
public class MeiPo implements InvocationHandler { private Object target; public Object getInstance(Object target){ this.target = target; return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Exception{ before(); Object obj = method.invoke(this.target, args); after(); return obj; } private void before(){ System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求"); System.out.println("开始物色"); } private void after(){ System.out.println("OK的话,准备办事"); } }
public class App { public static void main(String[] args) { IPerson p = (IPerson)new MeiPo().getInstance(new Girl()); p.findLove(); } }
以下是模拟jdk代理类而自定义实现的代理
/** * @Author long * @Date 2019/3/14 7:45 * 自定义类加载器 */ public class SelfClassLoader extends ClassLoader{ // 文件的路径 private File classPathFile; public SelfClassLoader(){ String classPath = SelfClassLoader.class.getResource("").getPath(); // 定义classPath为当前classPath System.out.println("classPath=" + classPath); this.classPathFile = new File(classPath); } // 重写查找类的方法,需传入类名 @Override protected Class<?> findClass(String name) throws ClassNotFoundException { //获取类的完全限定名 String className = SelfClassLoader.class.getPackage().getName() + "." + name; //不为空的情况下,创建一个指向所指定类的文件 if(classPathFile != null){ // 定位到具体的类下面 File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class"); // 如果该类已经存在,将该类加载到流中 if(classFile.exists()){ FileInputStream in = null; ByteArrayOutputStream out = null; try{ in = new FileInputStream(classFile); out = new ByteArrayOutputStream(); byte [] buff = new byte[1024]; int len; while ((len = in.read(buff)) != -1){ out.write(buff,0,len); } // 该步骤将类加载到内存中 return defineClass(className,out.toByteArray(),0,out.size()); }catch (Exception e){ e.printStackTrace(); } } } return null; } }
/** * @Author long * @Date 2019/3/13 7:52 * SelfInvocationHandler,类似jdk的InvocationHandler */ public interface SelfInvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
/** * @Author long * @Date 2019/3/13 7:50 * 自定义代理类,类似jdk代理类Proxy */ public class SelfProxy { // 定义的一些常量 private static final String ln = "\n"; private static final String tab = "\t"; private static final String doubleTab = "\t\t"; private static final String threeTab = "\t\t\t"; private static final String dynamicClassName = "$Proxy0"; /** * 该方法用于创建代理类,需要三个参数,类加载器ClassLoader,接口Interfaces,SelfInvocationHandler */ public static Object newProxyInstance(SelfClassLoader classLoader, Class<?>[] interfaces, SelfInvocationHandler handler) { //1.动态生成源代码.java文件 String src = generateSrc(interfaces); System.out.println(src); //2.将java文件输出到磁盘 String filePath = SelfProxy.class.getResource("").getPath(); File file = new File(filePath + dynamicClassName + ".java"); FileWriter fw = null; try { fw = new FileWriter(file); fw.write(src); } catch (IOException e) { e.printStackTrace(); } finally { try { fw.flush(); fw.close(); } catch (IOException e) { e.printStackTrace(); } } //3.编译成class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager = compiler.getStandardFileManager(null, null , null); Iterable iterable = manager.getJavaFileObjects(file); JavaCompiler.CompilationTask task = compiler.getTask(null,manager,null,null,null,iterable); task.call(); try { manager.close(); } catch (IOException e) { e.printStackTrace(); } //4.编译生成的class文件加载到jvm中 Class proxyClass = null; try { proxyClass = classLoader.findClass(dynamicClassName); } catch (ClassNotFoundException e) { e.printStackTrace(); } Constructor c = null; try { c = proxyClass.getConstructor(SelfInvocationHandler.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } file.delete(); //5.返回字节码重组以后的代理对象 Object result = null; try { result = c.newInstance(handler); } catch (Exception e) { e.printStackTrace(); } return result; } //生成动态代理类的流 private static String generateSrc(Class<?>[] interfaces) { StringBuffer buffer = new StringBuffer(); // 定义类的包路径 buffer.append("package gp.study.design.pattern.proxy.self;" + ln); // 引入需要用到的包 buffer.append("import java.lang.reflect.*;" + ln); buffer.append("import gp.study.design.pattern.proxy.house.RentAction;" + ln); // 定义代理类,实现给定的接口(传入的是接口数组,该出暂时默认实现一个第一个接口) buffer.append("public class " + dynamicClassName + " implements " + interfaces[0].getName() + "{" + ln); // 代理类中持有SelfInvocationHandler的引用 buffer.append(tab + "SelfInvocationHandler h;" + ln); // 创建代理类的构造方法,需要接受一个SelfInvocationHandler类型的参数 buffer.append(tab + "public "+dynamicClassName + " (SelfInvocationHandler h){" + ln); buffer.append(doubleTab + "this.h = h;" + ln); buffer.append(tab + "}" + ln); // 该处只实现第一个接口的所有方法 Method[] methods = interfaces[0].getMethods(); for (Method m : methods) { // getParameterTypes方法返回一个class对象数组,以声明顺序表示此Method对象表示的形式参数类型。如果没有参数,返回长度为0的数组。 Class<?>[] params= m.getParameterTypes(); // 该字符串用以拼接方法的参数名称 StringBuffer paramNames = new StringBuffer(); // 该字符串用以拼接方法的参数值 StringBuffer paramValues = new StringBuffer(); // 该字符串用以拼接方法的类型 StringBuffer paramClass = new StringBuffer(); // 遍历这些paramTypes,获取需要的值 for (int j = 0; j < params.length; j++) { Class clazz = params[j]; String type = clazz.getName(); String paramName = toLowerFirstCase(clazz.getSimpleName()); // 参数类型 + 参数名(默认类型小写) paramNames.append(type + " " + paramName); // 参数值(类型转小写的值) paramValues.append(paramName); // 参数的class paramClass.append(clazz.getName() + ".class"); // 如果有多个参数,需要用逗号分隔开 if (j < params.length -1) { paramNames.append(","); paramClass.append(","); paramValues.append(","); } } // 开始创建接口中的方法 buffer.append(tab + "public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames.toString() + "){" + ln); buffer.append(doubleTab + "try{" + ln); // 获取到接口的某个方法,通过调用类的getMethod方法 buffer.append(threeTab + "Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName()+ "\",new Class[]{"+ paramClass.toString() + "});" + ln); //代用SelfInvocationHandler的invoke方法,传入的参数为当前动态代理对象this,获取到的方法m,以及参数值 buffer.append(threeTab + (hasReturn(m.getReturnType()) ? "return " : "") + getCaseCode("this.h.invoke(this,m,new Object[]{" + paramValues + "})",m.getReturnType()) + ";" + ln); // 捕获相关的异常 buffer.append(doubleTab + "}catch(Error _ex){ }"+ ln); buffer.append(doubleTab + "catch(Throwable e){" + ln); buffer.append(threeTab + "throw new UndeclaredThrowableException(e);" + ln); buffer.append(doubleTab + "}"+ln); buffer.append(doubleTab + getReturnEmptyCode(m.getReturnType()) + ln); buffer.append(tab + "}" + ln); } buffer.append("}" + ln); return buffer.toString(); } private static Map<Class, Class> mapping = new HashMap<Class, Class>(); static { mapping.put(int.class, Integer.class); } private static String getReturnEmptyCode(Class<?> returnClass){ if(mapping.containsKey(returnClass)){ return "return 0;"; }else if(returnClass == Void.class){ return ""; }else { return "return null;"; } } private static String getCaseCode(String code,Class<?> returnClass){ if(mapping.containsKey(returnClass)){ return "((" + mapping.get(returnClass).getName() + ")" + code + ")." + returnClass.getSimpleName() + "Value()"; } return code; } // 判断是否有返回值 private static boolean hasReturn(Class<?> clazz) { return clazz != Void.class; } // 将某个字符串的首字母转小写 private static String toLowerFirstCase(String src) { char[] chars = src.toCharArray(); chars[0] += 32; return String.valueOf(chars); } }
public interface Person { int findLove(); }
/** * @Author long * @Date 2019/3/14 22:22 */ public class Girl implements Person { @Override public int findLove() { System.out.println("高富帅"); System.out.println("身高180cm"); System.out.println("有6块腹肌"); return 0; } }
/** * @Author long * @Date 2019/3/14 22:16 */ public class MeiPo implements SelfInvocationHandler { private Object target; public Object getInstance(Object target) throws Exception{ this.target = target; // 此处传入target的信息,是要实现target接口定义的方法,传入SelfInvocationHandler是为了调用invoke方法 return SelfProxy.newProxyInstance(new SelfClassLoader(), target.getClass().getInterfaces(), this); } // 该方法由动态代理类来调用,因为动态代理类持有该对象的引用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ before(); Object obj = method.invoke(this.target, args); after(); return obj; } private void before(){ System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求"); System.out.println("开始物色"); } private void after(){ System.out.println("OK的话,准备办事"); } }
/** * @Author long * @Date 2019/3/14 22:23 */ public class App { public static void main(String[] args) { try { Person obj = (Person) new MeiPo().getInstance(new Girl()); obj.findLove(); } catch (Exception e) { e.printStackTrace(); } } }