我们今天来看一下dubbox多出来的那个“x”都包含什么,当然一定会存在遗落,毕竟我是从一个第三方使用者的角度来总结的。之前也写了几篇关于dubbo的文章,虽然都加了dubbox
的tag,但这一篇才是真正的只与dubbox相关的哟~
RESTEasy不熟悉的童鞋(和我一样),不妨先看一些相关的技术文档,我这里粗糙的翻译了一篇,。随着你对RESTEasy的熟悉,你会发现dubbox中很多的新增特性都是RESTEasy带来的,遵循JAX-RS规范。当然dangdang的大牛们也做了很多工作,后面我们一点一点分析。
这里还要再次说一个关于RESTEasy的小,这也是最终有这篇文章的原因。
序列化部分,dangdang为dubbox新增了fst和kryo两种方式,使用方式和dubbo原有的保持一致,这一部分几乎是对业务透明的,之所以说是几乎,是因为不少大牛提到序列化这部分还是存在不少坑,这就需要我们在开发时进行比较全面的测试,由于我们目前还没正式投入使用,所以暂时就说这么多。
关于新增的servlet容器,目前知道的就是tomcat-embed,另外如果使用REST协议,还可以使用Tjws容器,不过RESEasy官方推荐这个玩意儿还是建议在测试环境中使用。当然,我们也可以选择使用server="servlet"
来使用外部的servlet容器,例如和其他应用使用同一个tomcat。但是文档上也叮嘱,即便是打算使用外部tomcat,也尽可能不要和其他应用混合部署,而应该用单独的实例。
其实上面说的这些,在dubbox提供的中都有详细的说明,多说只是重复。
源码解析
我们接下来看一下新增的RestProtocol
的具体实现。基于之前的分析结果,我们可以直接定位到核心的代码块(doExport):
protectedRunnable doExport(T impl, Class type, URL url) throws RpcException { String addr = url.getIp() + ":" + url.getPort(); //这么处理其实是为了配合dubbo的延迟暴露机制,延迟暴露的原理是创建新线程,所以ServiceImplHolder靠ThreadLocal来记录对应的类信息,而不是靠公共变量,避免竞争问题 Class implClass = ServiceImplHolder.getInstance().popServiceImpl().getClass(); //根据url中的地址创建server容器,相同地址的服务使用相同的容器 RestServer server = servers.get(addr); if (server == null) { server = serverFactory.createServer(url.getParameter(Constants.SERVER_KEY, "jetty")); //默认使用jetty,当当推荐使用tomcat server.start(url); servers.put(addr, server); } //查看implClass是否包含jax-rs注解 final Class resourceDef = GetRestful.getRootResourceClass(implClass) != null ? implClass : type; server.deploy(resourceDef, impl, getContextPath(url)); //在server中部署指定服务 final RestServer s = server; //注意这样的写法,java要求线程中只能使用外部final变量 return new Runnable() { public void run() { // TODO due to dubbo's current architecture, // it will be called from registry protocol in the shutdown process and won't appear in logs s.undeploy(resourceDef); } };}
该方法是继承自dubbo原有的AbstractProxyProtocol
类:
按照dubbo的逻辑,注意该方法最终返回的是一个可异步执行的callback类,完成的逻辑也很简单,就是从对应的server中把指定资源服务给“卸载”掉。
我们再来关注一下关于server
的逻辑,这部分其实很简单,根据你的配置直接创建对应的server:
public class RestServerFactory { private HttpBinder httpBinder; //提供http服务的容器 //该方法为SPI注入时调用,会注入一个httpBinder自适应扩展实例 public void setHttpBinder(HttpBinder httpBinder) { this.httpBinder = httpBinder; } public RestServer createServer(String name) { // TODO move names to Constants if ("servlet".equalsIgnoreCase(name) || "jetty".equalsIgnoreCase(name) || "tomcat".equalsIgnoreCase(name)) { return new DubboHttpServer(httpBinder); // } else if ("tjws".equalsIgnoreCase(name)) { // return new TjwsServer(); } else if ("netty".equalsIgnoreCase(name)) { return new NettyServer(); } else if ("sunhttp".equalsIgnoreCase(name)) { return new SunHttpServer(); } else { throw new IllegalArgumentException("Unrecognized server name: " + name); } }}
DubboHttpServer
类主要贡酒是完成了RESTEasy和servlet容器的绑定,上面代码的httpBinder
代表的就是你要使用的容器,例如tomcat。这部分逻辑你需要结合RESTEasy的初始化步骤来理解,我就不多说了。
tomcat-embed的使用方式,也非常的直观,结合官方提供的例子即可,也不多说了。