代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。java
package com.github.binarylei.design.proxy; public interface UserService { public void say(); } public class UserServiceImpl implements UserService { @Override public void say() { System.out.println("Hello World!"); } }
public void test() { UserServiceImpl obj = new UserServiceImpl(); UserService userService = new UserService() { @Override public void say() { System.out.println("这是静态代理"); obj.say(); } }; userService.say(); }
很明显静态代理每一个被代理的类都要手写一个代理类,当修改被代理的类时也要修改对应的代理类。解决这个问题则是由程序来生成对应的代理类,这就是动态代理。git
public void test1() throws Exception { UserServiceImpl obj = new UserServiceImpl(); UserService userService = (UserService) Proxy.newProxyInstance( UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { return method.invoke(obj, args); } else { System.out.println(proxy.getClass().getName()); System.out.println(method); Object ret = method.invoke(obj, args); return ret; } } }); userService.say(); System.out.println(userService); }
注意:JDK 中所要进行动态代理的类必需要实现一个接口 ,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具备必定的局限性,并且使用反射的效率也并非很高。github
使用 CGLib 实现动态代理,彻底不受代理类必须实现接口的限制,并且 CGLib 底层采用 ASM 字节码生成框架,使用字节码技术生成代理类,比使用 Java 反射效率要高。惟一须要注意的是,CGLib 不能对声明为 final 的方法进行代理,由于 CGLib 原理是动态生成被代理类的子类。编程
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.8</version> </dependency>
public void test2() { Enhancer enhancer = new Enhancer(); //1. 设置父类 enhancer.setSuperclass(UserServiceImpl.class); //2. 设置回调函数 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println(method + " proxy"); Object ret = proxy.invokeSuper(obj, args); return null; } }); //3. 获取代理对象 UserService userService = (UserService) enhancer.create(); userService.say(); }
参数:Object 为由 CGLib 动态生成的代理类实例,Method 为上文中实体类所调用的被代理的方法引用,Object[] 为参数值列表,MethodProxy 为生成的代理类对方法的代理引用。proxy.invokeSuper(obj, arg) 从代理实例的方法调用返回的值。设计模式
JDK 的动态代理其实是在内存中生成了一个字节码类,并进行编译,加载。JVM 生成的类名称都是以 $ 开头,eg: $Proxy0app
public void test1() throws Exception { UserServiceImpl obj = new UserServiceImpl(); UserService userService = (UserService) Proxy.newProxyInstance( UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(proxy.getClass().getName()); // $Proxy0 Object ret = method.invoke(obj, args); return ret; } }); userService.say(); System.out.println(userService); byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", obj.getClass().getInterfaces()); FileOutputStream out = new FileOutputStream( this.getClass().getResource("").getPath() + "$Proxy0.class"); out.write(bytes); }
查看生成的 $Proxy0.class 类以下:框架
import com.github.binarylei.design.proxy.UserService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements UserService { private static Method m3; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final void say() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m3 = Class.forName("com.github.binarylei.design.proxy.UserService").getMethod("say", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } // ... }
(1) 定义 MyInvocationHandler 接口ide
@FunctionalInterface public interface MyInvocationHandler { Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
(2) 实现本身的 MyProxy 类函数
package com.github.binarylei.design.proxy.my; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * @author: leigang * @version: 2018-10-02 */ public class MyProxy { public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, MyInvocationHandler h) { FileWriter out = null; try { // 1. 动态生成源代码 .java 文件 String src = generateSrc(interfaces); // 2. .java 文件生成到磁盘 File file = new File(MyProxy.class.getResource("").getPath() + "$Proxy1.java"); out = new FileWriter(file); out.write(src); out.flush(); out.close(); // 3. 把 .java 文件编译成 .class 文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager = compiler.getStandardFileManager( null, null, null); Iterable<? extends JavaFileObject> iterable = manager.getJavaFileObjects(file); JavaCompiler.CompilationTask task = compiler.getTask( null, manager, null, null, null, iterable); task.call(); manager.close(); // 4. 编译生成的 .class 类到 JVM 中 Class<?> clazz = Class.forName("com.github.binarylei.design.proxy.my.$Proxy1"); // 5. 返回字节码重组之后新代理对象 Constructor<?> constructor = clazz.getConstructor(MyInvocationHandler.class); return constructor.newInstance(h); } catch (Exception e) { e.printStackTrace(); } return null; } private static final String ln = "\r\n"; private static String generateSrc(Class<?>[] interfaces) { StringBuilder sb = new StringBuilder(); sb.append("package com.github.binarylei.design.proxy.my;").append(ln); sb.append("import com.github.binarylei.design.proxy.UserService;").append(ln); sb.append("import java.lang.reflect.Method;").append(ln); sb.append("public final class $Proxy1 implements ").append(interfaces[0].getSimpleName()).append(" {").append(ln); sb.append("private static MyInvocationHandler h;").append(ln); sb.append("public $Proxy1(MyInvocationHandler h) throws Exception {").append(ln); sb.append("this.h = h;").append(ln); sb.append("}").append(ln); for (Class<?> clazz : interfaces) { Method[] methods = clazz.getMethods(); for (Method m : methods) { sb.append("public final void say() {").append(ln); sb.append("try {").append(ln); sb.append("Method m = Class.forName(\"").append(clazz.getName()).append("\").getMethod(\"") .append(m.getName()).append("\", new Class[0]);").append(ln); sb.append("h.invoke(this, m, (Object[]) null);").append(ln); sb.append("} catch (Throwable e) {").append(ln); sb.append("e.printStackTrace();").append(ln); sb.append("}").append(ln); sb.append("}").append(ln); } } sb.append("}").append(ln); return sb.toString(); } }
(3) 测试测试
public void test3() { UserServiceImpl obj = new UserServiceImpl(); UserService userService = (UserService) MyProxy.newProxyInstance( UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), new MyInvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(proxy.getClass().getName()); System.out.println(method); Object ret = method.invoke(obj, args); return ret; } }); userService.say(); System.out.println(userService); }
参考:
天天用心记录一点点。内容也许不重要,但习惯很重要!