微信公众号:bugstack虫洞栈 沉淀、分享、成长,专注于原创专题案例,以最易学习编程的方式分享知识,让自己和他人都能有所收获。目前已完成的专题有;Netty4.x实战专题案例、用Java实现JVM、基于JavaAgent的全链路监控、手写RPC框架、架构设计专题案例[Ing]等。欢迎:star:Star和使用,你用剑 、我用刀:hocho:,好的代码都很烧:smirk:,望你不吝出招:dash:!
在Java中动态代理是非常重要也是非常有用的一个技术点,如果没有动态代理技术几乎也就不会有各种优秀框架的出现,包括Spring。 其实在动态代理的使用中,除了我们平时用的Spring还有很多中间件和服务都用了动态代理,例如;
动态代理可以使用Jdk方式也可以使用CGLB,他们的区别,如下;
类型 | 机制 | 回调方式 | 适用场景 | 效率 |
---|---|---|---|---|
JDK | 委托机制,代理类和目标类都实现了同样的接口,InvocationHandler持有目标类,代理类委托InvocationHandler去调用目标类的原始方法 | 反射 | 目标类是接口类 | 效率瓶颈在反射调用稍慢 |
CGLIB | 继承机制,代理类继承了目标类并重写了目标方法,通过回调函数MethodInterceptor调用父类方法执行原始逻辑 | 通过FastClass方法索引调用 | 非接口类,非final类,非final方法 | 第一次调用因为要生成多个Class对象较JDK方式慢,多次调用因为有方法索引较反射方式快,如果方法过多switch case过多其效率还需测试 |
itstack-demo-test └── src ├── main │ └── java │ └── org.itstack.demo │ ├── proxy │ │ └── cglib │ │ └── CglibProxy.java │ ├── jdk │ │ ├── reflect │ │ │ ├── JDKInvocationHandler.java │ │ │ └── JDKProxy.java │ │ └── util │ │ └── ClassLoaderUtils.java │ └── service │ ├── IUserService.java │ └── UserService.java └── test └── java └── org.itstack.demo.test └── ApiTest.java 复制代码
service/IUserService.java
public interface IUserService { String queryUserNameById(String userId); } 复制代码
service/UserService.java
public class UserService implements IUserService { public String queryUserNameById(String userId) { return "hi user " + userId; } } 复制代码
reflect/JDKInvocationHandler.java & 代理类反射调用
public class JDKInvocationHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method.getName()); return "我被JDKProxy代理了"; } } 复制代码
reflect/JDKProxy.java & 定义一个代理类获取的服务
public class JDKProxy { public static <T> T getProxy(Class<T> interfaceClass) throws Exception { InvocationHandler handler = new JDKInvocationHandler(); ClassLoader classLoader = ClassLoaderUtils.getCurrentClassLoader(); T result = (T) Proxy.newProxyInstance(classLoader, new Class[]{interfaceClass}, handler); return result; } } 复制代码
ApiTest.test_proxy_jdk() & 执行调用并输出反射类的字节码
@Test public void test_proxy_jdk() throws Exception { IUserService proxy = (IUserService) JDKProxy.getProxy(ClassLoaderUtils.forName("org.itstack.demo.service.IUserService")); String userName = proxy.queryUserNameById("10001"); System.out.println(userName); String name = "ProxyUserService"; byte[] data = ProxyGenerator.generateProxyClass(name, new Class[]{IUserService.class}); // 输出类字节码 FileOutputStream out = null; try { out = new FileOutputStream(name + ".class"); System.out.println((new File("")).getAbsolutePath()); out.write(data); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (null != out) try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } 复制代码
queryUserNameById 我被JDKProxy代理了 复制代码
部分内容抽取,可以看到比较核心的方法,也就是我们在调用的时候走到了这里
public final String queryUserNameById(String paramString) throws { try { return (String)this.h.invoke(this, m3, new Object[] { paramString }); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("org.itstack.demo.service.IUserService").getMethod("queryUserNameById", new Class[] { Class.forName("java.lang.String") }); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } 复制代码
cglib/CglibProxy.java
public class CglibProxy implements MethodInterceptor { public Object newInstall(Object object) { return Enhancer.create(object.getClass(), this); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("我被CglibProxy代理了"); return methodProxy.invokeSuper(o, objects); } } 复制代码
ApiTest.test_proxy_cglib() & 调用代理类
@Test public void test_proxy_cglib() { CglibProxy cglibProxy = new CglibProxy(); UserService userService = (UserService) cglibProxy.newInstall(new UserService()); String userName = userService.queryUserNameById("10001"); System.out.println(userName); } 复制代码
我被CglibProxy代理了 hi user 10001 复制代码