dubbo分析
dubbo为什么要对接spring,如何无缝对接
原因比较简单,首先就是spring在开发环境的成熟以及使用的易用都是好评,spring本身的扩展成本也不高
关于xsd:schema的各个属性具体含义就不作过多陈述,大家可以参见
http://www.w3school.com.cn/sc...
DubboBeanDefinitionParser和DubboNamespaceHandler的完成了对schemas的实现。源码暂且另说,
dubbo为什么扩展性好,是如何实现的?
ExtensionLoader dubbo核心类。
dubbo扩展性好主要在于它的插件形式,针对业务什么技术好就用什么(只针对在rpc架构的要点方面)
通过插件机制解耦依赖来实现框架设计原则中的针对接口编程而不针对实现。 如果属性ExtensionLoader就属性了dubbo的扩展。
提到扩展,我们看看jdk的service provider interface,后文用SPI简写,主要解耦机制比较强势体现。经常看源码的同学应该很熟了吧,于dubbo的SPI对比。
jdk-spi:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
各种jdbc驱动,log4j,spring对servlet3.0规范对ServletContainerInitializer的实现等。JDK的SPI是加载所有的实现,这里好像又得说到类加载器,可以自己去看看相关的文章。而dubbo只加载自己所想要的。
dubbo的SPI是对jdk的封装,来满足自己的特性。
dubbo-spi:dubbo的加载是单例模式,可以延迟加载
ExtensionLoader
| +-getAdativeExtension #获取扩展的适配器类#
| +-createAdativeExtension #缓存中没有就创建一个#
| +-getAdativeExtensionClasses #获取适配器类#
| +-getExtensionClass #加载所有扩展点实现类#
| \-createAdativeExtansionClass #dubbo帮我们动态创建一个适配器类
大致的流程如此,源码暂时先不详解了。
简而言之,dubbo的特性
dubbo 的动态代理
dubbo自己实现了一套代理机制
/*com.alibaba.dubbo.common.bytecode.Proxy*/
public abstract class Proxy
{
private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
public static final InvocationHandler RETURN_NULL_INVOKER = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args){ return null; }
};
public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args){ throw new UnsupportedOperationException("Method [" + ReflectUtils.getName(method) + "] unimplemented."); }
};
private static final Map<ClassLoader, Map<String, Object>> ProxyCacheMap = new WeakHashMap<ClassLoader, Map<String, Object>>();
private static final Object PendingGenerationMarker = new Object();
根据申明的这些final static对象我们可以大概知道dubbo自己的需求
缓存机制: 遍历所有入参接口+";"作为Key
/**
* get method desc.
* int do(int arg1) => "do(I)I"
* void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
* /
版本机制: 通过 PROXY_CLASS_COUNTER 作为单个版本号,规则大概为 pkg + ".poxy"+id,保证了没有冲突
// create ProxyInstance class.
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{ InvocationHandler.class }, new Class<?>[0], "handler=$1;");
ccp.addDefaultConstructor();
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
// create Proxy class.
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class<?> pc = ccm.toClass();
proxy = (Proxy)pc.newInstance();
dubbo的新版维护
2.5.4 解决问题和新功能
优雅的关机
MonitorFilter阻止RPC进程
动态配置:不能指定消费者IP,提供者端的配置不能被删除。
路由规则解析问题
异步会影响下游的RPC调用。
供应商方面的流量控制优化。
社区报告的一些错误修正。
2.5.6解决问题和新功能
修复了PojoUtils问题:枚举类型,私有文件。
当提供程序线程池耗尽时,RejectException不能发送到使用者端。
当负载过载时避免不必要的响应传输。
Slf4jLogger可以反映实际的行号。
使用延迟导出时,并发会导致意外的多端口绑定
当没有提供者时,模拟不会工作。
一些优化:OverrideListener,在提供程序上停止不必要的心跳,Main Bootstrap进程等。
一些错误修正:动态配置不能删除,telnet invoke支持json参数,监控统计问题等
新功能
支持Netty4 手册
线程池耗尽时自动堆栈转储。手册
Jdk 1.8新的日期时间类型支持hessian2序列化。
2.5.7解决问题和新功能
全新的注释配置实现,修复了旧注释版本报告的所有缺陷。(dubbo-spring-boot-starter将在稍后发布)
*更多详情请参阅Dubbo Annotation-Driven
支持读取IP和端口以注册和绑定环境变量。
例
调整一些XML配置项目:dump.directory等。
Bootstrap在注册表无法连接时被阻止。
MonitorService在第一次调用MonitorService时无法连接ZK时阻止RPC进程。
标记内部的JSON序列化已弃用,请改用fastjson。
RMI协议支持附件传递。
EnumSet类型支持hessian2序列化。
修复了一些错误和优化。
2.5.8解决问题和新功能
Dubbo编程模型增强。
修复了2.5.7中报告的一些错误。
更多细节请参阅Dubbo注解驱动
外部配置EnableDubbo,EnableDubboBindings也为Spring-Boot-Starter做准备。
更多细节请参阅Dubbo外部化配置
通过telnet和更强大的OPShttp:仅支持online,offline在此版本中,将在以下版本中提供更多功能
路由规则不应该每次都默认运行
优化春季活动表现
修复了使用策展人时的NPE路径问题
修复了使用dubbo-admin报告的一些错误
Redis注册表支持认证
2.5.9解决问题和新功能
bug
向后兼容RMI协议
Hessian序列化:
为java.util.Time类型添加空检查
恢复hessian的覆盖序列,子类的字段应该覆盖父类的字段,而不是其他方式
Redis和多播注册表不能脱机。
增加功能
注释增强。基于这个版本的dubbo-spring-boot-starter也已经发布。
为qos添加开关:dubbo.application.qos.enable=true/false。例如,注意我们配置qos的新方法,dubbo.qos.port已被更改为dubbo.application.qos.port。
正常关机,在注册表取消注册和线程池关闭之间增加额外的等待时间。
通过避免使用低效率来提高黑森序列化的性能synchronized。
参数验证失败时避免重试。
条件路由器还应检查默认值。
解决漏洞
在这个版本中,我们将检查从网络接收到的序列化标识(只有当标识JDK序列化时)与当前实例中的标识匹配。如果无法匹配,则反序列化过程将被拒绝。由于原来的JDK反序列化有安全问题,我们这样做是为了防止序列化类型,例如从意外篡改hessian2来java。
2.5.10解决问题和新功能
bug
FutureUnapter中的TimeUnit转换错误。
在Docker中部署时,提供者端无法调用服务
Hessian序列化问题类型:short和byte。
删除isdestrory()在注册表中检查,确保在关闭时取消注册
引用注释支持注释类型上的注释
2.6.0解决问题和新功能
在本次发布中,我们主要合并了当当网贡献的dubbox分支,突出了以下功能:
REST支持(通过整合resteasy)
高性能的序列化框架:kryo,FST
嵌入式tomcat支持
我们试图保留原来的分支,同时进行以下小调整:
升级了一些依赖的版本:kryo,FST和tomcat
删除了对核心RPC协议的更改以避免兼容性问题