RPC的调用对用户来说是透明的,内部具体是如何实现呢?java
核心技术采用的就是动态代理,RPC 会自动给接口生成一个代理类,当咱们在项目中注入初始化接口的时候,运行过程当中实际绑定的是这个接口生成的代理类。
在接口方法被调用的时候,它其实是被生成代理类拦截到了,这样就能够在生成的代理类里面,加入其余调用处理逻辑。
实现代码:安全
public class JDKDynamicProxy { public static void main(String[] args){ // 构建代理器 JDKProxy proxy = new JDKProxy(new Teacher()); ClassLoader classLoader = JDKDynamicProxy.class.getClassLoader(); // 生成代理类 User user = (User) Proxy.newProxyInstance(classLoader, new Class[]{User.class}, proxy); // 接口调用 System.out.println(user.job()); } /** * 定义用户的接口 */ public interface User { String job(); } /** * 实际的调用对象 */ public static class Teacher { public String invoke(){ return "i'm a Teacher"; } } /** * 建立JDK动态代理类 */ public static class JDKProxy implements InvocationHandler { private Object target; JDKProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] paramValues) { return ((Teacher)target).invoke(); } } }
反编译生成的代理类能够知道,代理类 $Proxy里面会定义相同签名的接口(也就是上面代码User的job接口),而后内部会定义一个变量绑定JDKProxy代理对象,当调用User.job接口方法,实质上调用的是JDKProxy.invoke()方法,从而实现了接口的动态代理。框架
服务接口ide
编写订单服务的下单接口:
public class OrderService { /** * 下单接口 */ public String placeOrder(String userName) { System.out.println("用户:" + userName + "开始下单"); return "成功"; } }
代理实现工具
实现MethodInterceptor接口, 重写intercept方法, 能够追加校验逻辑、日志记录等功能。
public class OrderServiceCglib implements MethodInterceptor { public Object getProxy(Object target) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); // 设置回调方法 enhancer.setCallback(this); // 建立代理对象 return enhancer.create(); } /** * 实现MethodInterceptor接口中重写的方法 */ @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("校验下单参数:" + Arrays.asList(args)); Object result = proxy.invokeSuper(object, args); System.out.println("记录下单日志结果: " + result); return result; } }
(1) Cglib 动态代理性能
Cglib是一个强大的、高性能的代码生成包,它普遍被许多AOP框架使用,支持方法级别的拦截。它是高级的字节码生成库,位于ASM之上,ASM是低级的字节码生成工具,ASM的使用对开发人员要求较高,相比较来说, ASM性能更好。this
(2) Byte Buddy 字节码加强库编码
Byte Buddy是致力于解决字节码操做和 简化操做复杂性的开源框架。Byte Buddy 目标是将显式的字节码操做隐藏在一个类型安全的领域特定语言背后。它属于后起之秀,在不少优秀的项目中,像 Spring、Jackson 都用到了 Byte Buddy 来完成底层代理。相比 Javassist,Byte Buddy 提供了更容易操做的 API,编写的代码可读性更高。spa
(3) Javassist 动态代理设计
一个开源的分析、编辑和建立Java字节码的类库。javassist是jboss的一个子项目,它直接使用java编码的形式,不须要了解虚拟机指令,能够动态改变类的结构,或者动态生成类。Javassist 的定位是可以操纵底层字节码,因此使用起来并不简单,Dubbo 框架的设计者为了追求性能花费了很多精力去适配javassist。
Byte Buddy、 CGLIB、 Javassist、 JDK动态代理性能比较:
综合结果:
单位是纳秒。大括号内表明的是样本标准差,综合结果:Byte Buddy > CGLIB > Javassist> JDK。
本文由mirson创做, 但愿对你们有所帮助, 谢谢!