GenericException
(以前也在开发的过程当中也遇到了,还不是太懂,没有去解决)文章源码及部分讲解源自《深刻理解Apache Dubbo实战》 dubbo version:2.7.1
前端
在各类百度的过程当中,和我预期的不太同样。找到了一篇看着还行的文章,先留着,看其余的文章时发现都是如出一辙的,并且版本停留的比较前,不过关于dubbo的泛化调用也一直没怎么变。java
过滤器链组装:
在服务暴露的过程当中会使用Protocol层,ProtocolFilterWrapper
实现组装。在暴露与引用的过程当中,会使用ProtocolFilterWrapper#buildInvokerChain
方法组装整个过滤器apache
// 1-服务暴露时会调用buildInvokerChain @Override public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } // Constants.PROVIDER->根据Constants.PROVIDER标识本身是提供者类型的调用链(group) return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER)); } // 引用远程服务的时候也会调用buildInvokerChain @Override public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { return protocol.refer(type, url); } // Constants.CONSUMER->根据Constants.CONSUMER标识消费者类型的调用链(group) return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER); }
#### 构造调用链源码json
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) { Invoker<T> last = invoker;// 保存引用,后续用于把真正的调用者保存在过滤器的最后 // 得到全部的过滤器 List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); if (!filters.isEmpty()) { // 对过滤器作倒排遍历,即从尾到头。在构造的过程当中会从一直往上构造,因此调用顺序仍是头为第一个节点 for (int i = filters.size() - 1; i >= 0; i--) { final Filter filter = filters.get(i); // 把last节点变成next节点,并放到Filter链的next中 final Invoker<T> next = last; last = new Invoker<T>() { ···省略 @Override public Result invoke(Invocation invocation) throws RpcException { // 设置过滤器链的下一个节点,不断循环造成过滤链 Result result = filter.invoke(next, invocation); // 异步调用和同步调用的处理 if (result instanceof AsyncRpcResult) { AsyncRpcResult asyncResult = (AsyncRpcResult) result; asyncResult.thenApplyWithContext(r -> filter.onResponse(r, invoker, invocation)); return asyncResult; } else { return filter.onResponse(result, invoker, invocation); } } @Override public void destroy() { invoker.destroy(); } @Override public String toString() { return invoker.toString(); } }; } } return last; }
用于服务提供者端,实现泛化调用,实现序列化的检查和处理
Result result = invoker.invoke(new RpcInvocation(method, args, inv.getAttachments())); if (result.hasException() && !(result.getException() instanceof GenericException)) { return new RpcResult(new GenericException(result.getException())); }
上述代码是实现Filter#invoke方法,在执行完后会判断Result中是否有异常,若不是GenericException会包装为GenericException异常再返回。app
我在提供者作了自定义异常的处理,可是被包装了,并不能直接返回到前端被捕获。异步
下面我加入了判断:async
if (result.hasException() && !(result.getException() instanceof GenericException)) { // 处理自定义异常 String className = result.getException().getClass().getName(); if (className.startsWith("com.changyuan.education.commons.exception")) { // 打印堆栈 result.getException().printStackTrace(); // 返回异常信息 return new RpcResult(new ResultBean().failure(result.getException().toString())); } return new RpcResult(new GenericException(result.getException())); }
// 重写的toString,转为json对象 @Override public String toString() { return "{\"code\":" + code + ",\"msg\":\"" + msg + "\"}"; }
public ResultBean<T> failure(String upExcetionJson) { JSONObject jsonObject = JSON.parseObject(upExcetionJson); this.code = (int) jsonObject.get("code"); this.msg = jsonObject.get("msg"); return this; }
@Activate(group = Constants.PROVIDER, order = -20000) public class Dubbo2GenericFilter implements Filter { }
在resources中建立文件夹META-INF.dubbo.internal
,建立文件org.apache.dubbo.rpc.Filter
,写入一下内容ide
generic=com.changyuan.education.exam.filter.Dubbo2GenericFilter
Dubbo SPI 和Java SPI相似,须要在META-INF/dubbo/下放置对应的SPI配置文件,文件名称必须命名为接口的全路径名。配置文件的内容为key=扩展点实现类的全路径名,多个实现用换行符隔开。其中key会被做为Dubbo SPI注解中传入的参数。Dubbo会默认扫描三个文件夹META-INF/dubbo/、META-INF/services/、META-INF/dubbo/internal/ui