-
代理模式(Proxy)
-
结构型
-
目标对象
- 被代理人
- 这件事一定要做,但是没时间坐或者不想做
- 做最终决定方法
- 代理人
- 执行者
- 拿到被代理人的引用
- 能够调用被代理人的做最终决定的方法
- 只参与过程或者过程的某几个环节
- 被代理人
-
为其他对象提供一种代理,以控制对这个对象的访问
-
结构上与 Decorator 类似,但 Proxy 是控制,更像是一种对功能的限制,而 Decorator 是增加职责
-
Spring 的 Proxy 模式在 AOP 中有体现,比如 JdkDynamicAopProxy 与 Cglib2AopProxy
-
作用
- AOP 实现
- 拦截器
- 解耦
-
生活场景
- 房屋中介
- 售票黄牛
- 婚介所
- 经纪人
- 快递
- 事物代理
- 非嵌入式日志监听
-
模式
-
静态代理
- 在代理之前所有东西都是已知的
- 扩展性差
- 人工
package source.patterns.proxy.staticed; /** * 代理人接口 * 静态代理缺点:会有很多其他可代理的方法,但单一被代理人无法完成,如租房,购物... */ public interface Person { void findLove(); } package source.patterns.proxy.staticed; /** * 被代理人 */ public class Son implements Person{ /** * 做决定的方法,但没有时间自己去做 */ public void findLove(){ System.out.println("找对象:肤白貌美大长腿"); } } package source.patterns.proxy.staticed; /** * 代理人 */ public class Father { private final Son son; /** * 静态代理:类是固定的,不能代理其他类 */ public Father(Son son){ // 拿到被代理人的引用 this.son = son; } public void findLove(){ System.out.println("根据你得要求物色"); // 让被代理人做决定 son.findLove(); System.out.println("双方服务是否同意"); } } package source.patterns.proxy.staticed; /** * 代理人 */ public class Matchmaking { private final Person person; public Matchmaking(Person person){ this.person = person; } public void findLove(){ System.out.println("婚介根据你的需求找对象"); person.findLove(); System.out.println("自己绝对合适不合适"); } }
-
动态代理
-
在代理之前所有东西都是未知的
-
扩展性强
-
自动化
-
实现形式
-
JDK
public interface Person { void findLove(); void findWork(); } /** * 代理人:可以随便扩展,找对应的代理人 */ public class Mark implements Person{ @Override public void findLove(){ System.out.println("高富帅"); } @Override public void findWork() { System.out.println("找工作"); } } /** * 被代理人 */ public class Matchmaking implements InvocationHandler { private Person person; public Object getInstance(Person person){ this.person = person; Class<?> clz = person.getClass(); //用来生成一个新的对象(字节码重组来实现) return Proxy.newProxyInstance(clz.getClassLoader(),clz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("婚介开始帮忙找对象"); method.invoke(this.person,args); System.out.println("合适的话结账,不合适的话继续"); return null; } } public class JobIntroduction implements InvocationHandler { private Person person; public Object getInstance(Person person){ this.person = person; Class<?> clz = person.getClass(); return Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始找工作"); method.invoke(this.person, args); System.out.println("工作找完了"); return null; } }
-
CGLIB
- 原理:字节码重组
- 通过反射拿到被代理对象的引用,并且获取到它所有的接口
- 通过 JDK Proxy 类重新生成一个新的类
- 动态的生成一些 Java 代码,把新加的业务逻辑用一定的逻辑用代码去调用
- 编译新生成的 Java 代码
- 再重新加载到 jvm 中运行
- JDK 规范:$符号开头的一般都是自动生成的,如内部类
- 通过反编译工具可以查看源代码
/** * 被代理人 */ public class Tom { public void findLove(){ System.out.println("只为结婚"); } } /** * 代理人:需要 cglib.jar * cglib.jar 依赖于 asm.jar * cglib-3.3.0 会发出非法反射的警告 */ public class Matchmaking implements MethodInterceptor { public Object getInstance(Class<?> clz){ Enhancer enhancer = new Enhancer(); // 要把哪个类设置为即将生成的新类的父类 enhancer.setSuperclass(clz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //业务的增强 System.out.println("开始找对象"); methodProxy.invokeSuper(o,objects); System.out.println("找完了"); return o; } }
- 原理:字节码重组
-
自己写动态代理
public interface MyInvocationHandler { Object invoke(Object object, Method method,Object[] objects) throws InvocationTargetException, IllegalAccessException; } /** * 编译生成的.class 文件加载到 JVM 中 */ public class MyClassLoader extends ClassLoader{ private final File classPathFile; public MyClassLoader(){ final String path = MyClassLoader.class.getResource("").getPath(); this.classPathFile = new File(path); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String className = MyClassLoader.class.getPackage().getName()+"."+name; if(classPathFile!=null){ final File file = new File(classPathFile,name.replaceAll("\\.","/")+".class"); if(file.exists()){ FileInputStream fileInputStream = null; ByteArrayOutputStream byteArrayOutputStream = null; try { fileInputStream = new FileInputStream(file); byteArrayOutputStream = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int len; while((len = fileInputStream.read(bytes))!=-1) byteArrayOutputStream.write(bytes,0,len); return defineClass(className, byteArrayOutputStream.toByteArray(), 0, byteArrayOutputStream.size()); } catch (IOException e) { e.printStackTrace(); }finally { try { if(fileInputStream!=null) fileInputStream.close(); if(byteArrayOutputStream!=null) byteArrayOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } return null; } } public class MyProxy { public static final String ln = "\r\n"; public static int num = 0; public static Object newProxyInstance(MyClassLoader classLoader,Class<?>[] interfaces,MyInvocationHandler invocationHandler){ // 1.动态生成源代码.java 文件 final String src = generateSrc(interfaces); // 2.把.java 文件输出到磁盘 final String path = MyProxy.class.getResource("").getPath(); final File file = new File(path,"$MyProxy"+num+".java"); FileWriter fileWriter = null; try { fileWriter = new FileWriter(file); fileWriter.write(src); fileWriter.flush(); } catch (IOException e) { e.printStackTrace(); }finally { if(fileWriter!=null) { try { fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } // 3.把生成的.java 文件编译成.class 文件 final JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler(); final StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null); final Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file); final JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects); task.call(); try { standardFileManager.close(); } catch (IOException e) { e.printStackTrace(); } // 4.编译生成的.class 文件加载到 JVM 中 try { final Class<?> $MyProxy0 = classLoader.findClass("$MyProxy"+num); final Constructor<?> constructor = $MyProxy0.getConstructor(MyInvocationHandler.class); // 5.返回字节码重组以后的新的代理对象 file.delete(); num++; return constructor.newInstance(invocationHandler); } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } return null; } private static String generateSrc(Class<?>[] interfaces){ final StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("package source.patterns.proxy.dynamic.custom;").append(ln); final Type[] genericInterfaces = interfaces[0].getGenericInterfaces(); if(genericInterfaces.length!=0){ for(Type type:genericInterfaces){ stringBuffer.append("import ").append(type.getTypeName()).append(";").append(ln); } } stringBuffer.append("import java.lang.reflect.Method;").append(ln); stringBuffer.append("public class $MyProxy").append(num).append(" implements ").append(interfaces[0].getName()).append("{").append(ln); stringBuffer.append("MyInvocationHandler h;").append(ln); stringBuffer.append("public $MyProxy").append(num).append("(MyInvocationHandler h){").append(ln); stringBuffer.append("this.h = h;").append(ln); stringBuffer.append("}").append(ln); int i = 0; for(Method method:interfaces[0].getMethods()){ stringBuffer.append("public ").append(method.getReturnType().getName()).append(" ").append(method.getName()).append("(){").append(ln); stringBuffer.append("try{").append(ln); stringBuffer.append("Method method").append(i).append(" = ").append(interfaces[0].getName()).append(".class.getMethod(\"").append(method.getName()).append( "\",new Class[]{});").append(ln); stringBuffer.append("this.h.invoke(this,method").append(i).append(",null);").append(ln); stringBuffer.append("}catch(Exception e){").append(ln); stringBuffer.append("e.printStackTrace();").append(ln); stringBuffer.append("}"); i++; } stringBuffer.append("}").append(ln); stringBuffer.append("}"); return String.valueOf(stringBuffer); } }
-
-
-
-