上一节讲解了resteasy如何使用fastjson来替换默认的jackson,虽然dubbox内部采用的就是resteasy,但是大多数情况下,dubbox服务是一个独立的app,并不需要以war包形式部署在外置容器中,也就没有web.xml。好在dubbox扩展性不错,很容易扩展,有此类需求的可以参考下面的做法:
一、rest协议指定fastjson做为序列化
<dubbo:protocol name="rest" port="8080" server="tomcat" contextpath="/" serialization="fastjson" charset="GBK"/>
注意这里的:serialization="fastjson" charset="GBK" 这里指定了采用fastjson作为json序列化的框架,同时字符编码格式为GBK。
二、修改BaseRestServer源码
dubbo采用了"URL总线"设计思想,所有服务的信息,最终都拼成一个URL注册到zk中, com.alibaba.dubbo.rpc.protocol.rest.BaseRestServer的start方法里,可以拿到这些URL的信息,参考以下代码:
public void start(URL url) { getDeployment().getMediaTypeMappings().put("json", "application/json"); getDeployment().getMediaTypeMappings().put("xml", "text/xml"); getDeployment().getProviderClasses().add(RpcContextFilter.class.getName()); //增加对serialization、charset的解析 杨俊明 2017-04-26 String serialization = url.getParameter("serialization"); if (StringUtils.isNotEmpty(serialization)) { String charset = url.getParameter("charset", "UTF-8"); if (serialization.equals("fastjson")) { getDeployment().setRegisterBuiltin(false); getDeployment().getScannedProviderClasses().clear(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect); fastJsonConfig.setCharset(Charset.forName(charset)); FastJsonProvider jsonProvider = new FastJsonProvider(); jsonProvider.setCharset(Charset.forName(charset)); jsonProvider.setFastJsonConfig(fastJsonConfig); ResteasyProviderFactory.getInstance().register(jsonProvider); getDeployment().setProviderFactory(ResteasyProviderFactory.getInstance()); } } getDeployment().getProviderClasses().add(RpcExceptionMapper.class.getName()); loadProviders(url.getParameter(Constants.EXTENSION_KEY, "")); doStart(url); }
上述代码7-22行,解释下,如果URL里指定了serialization而且是fastjson,就把默认的其它已经扫描到的provider清空,同时注册一个FastJsonProvider。为了满足各种编码格式的要求,对charset也一并做了解析,并传递到FastJsonConfig中。
注:上述代码已经提交到github的个人dubbox分支,需要的朋友们直接down最新源码即可。
三、405 Method Not Allowed 等状态码的处理
与上一节的处理方式类似,自己扩展一个ExceptionHandler即可,然后在dubbox中参考以下配置:
<dubbo:protocol name="rest" ... extension="xxx.xxx.NotAllowedExceptionHandler,xxx.xxx.NotSupportedExceptionHandler" serialization="fastjson" />
extension这里可以随意扩展,多个扩展之间用英文逗号分隔即可,读取extensions的源代码见com.alibaba.dubbo.rpc.protocol.rest.BaseRestServer#loadProviders
protected void loadProviders(String value) { for (String clazz : Constants.COMMA_SPLIT_PATTERN.split(value)) { if (!StringUtils.isEmpty(clazz)) { getDeployment().getProviderClasses().add(clazz.trim()); } } }