微服务框架(十一)Dubbo调用拦截及参数校检扩展

简介:   此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。   使用Dubbo框架时,面对自身的业务场景,需根据定制的需求编写SPI拓展实现,再根据配置来加载拓展点。

  此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。
  使用Dubbo框架时,面对自身的业务场景,需根据定制的需求编写SPI拓展实现,再根据配置来加载拓展点。本文为Dubbo调用拦截及参数校检扩展

本系列文章中所使用的框架版本为Spring Boot 2.0.3-RELEASE,Spring 5.0.7-RELEASE,Dubbo 2.6.2。

Dubbo SPI拓展点

Dubbo 的扩展点加载从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来。
Dubbo改进了 JDK 标准的 SPI的一些问题,详见拓展点加载

约定

在扩展类的 jar包内 ,放置扩展点配置文件META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。

示例

以扩展 Dubbo 的协议为例,在协议的实现 jar 包内放置文本文件:META-INF/dubbo/com.alibaba.dubbo.rpc.Filter,内容为:

global=com.test.filter.GlobalExceptionFilter

使用配置

Dubbo 配置模块中,扩展点均有对应配置属性或标签,通过配置指定使用哪个扩展实现。比如:

XML: <dubbo:provider filter="global" />

properties: dubbo.provider.filter = global

拓展项目路径

project
|-- pom.xml
`-- src
    `-- main
        |-- resources
        |    `-- META-INF
        |        `-- dubbo
        |           `-- com.alibaba.dubbo.rpc.Filter
        |-- java
             `-- com.test.filter
                  `-- GlobalExceptionFilter.java

调用拦截拓展

Filter SPI

// before filter
Result result = invoker.invoke(invocation);
// after filter

@SPI
public interface Filter {
   

    /**
     * do invoke filter.
     * <p>
     * <code>
     * // before filter
     * Result result = invoker.invoke(invocation);
     * // after filter
     * return result;
     * </code>
     *
     * @param invoker    service
     * @param invocation invocation.
     * @return invoke result.
     * @throws RpcException
     * @see com.alibaba.dubbo.rpc.Invoker#invoke(Invocation)
     */
    Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
}

实现Filter接口

public class GlobalExceptionFilter<T> implements Filter {
   }

GlobalExceptionFilter

逻辑为依层级捕捉消化异常,转换为相应的响应码

try {
   
    Result result = invoker.invoke(invocation);

    try{
   
        Throwable exception = result.getException();
    } catch (Throwable e) {
   
        // ExceptionFilter Warn
    }

} catch(RuntimeException e){
   
    // ConstraintViolationException Error

    // RpcException Error

    // Other RuntimeException Error
} catch (Exception e) {
   
    // Exception Error
}

Validation Error

if (e.getCause() != null
        && e.getCause() instanceof ConstraintViolationException) {
   
    ConstraintViolationException exs = (ConstraintViolationException) e
            .getCause();

    Set<ConstraintViolation<?>> violations = exs
            .getConstraintViolations();
    for (ConstraintViolation<?> item : violations) {
   
        /** 获取校检首个失败原因 */
        errorMsg = item.getMessage();
        break;
    }

    resp = Resp.createError(RespCode.PARAM_ERR,
            "input.param.error", errorMsg);
}

参数校检拓展

校检器

根据校检器工厂创建校检器

@SuppressWarnings({
     "unchecked", "rawtypes" })
public GlobalValidator(URL url) {
    
    this.clazz = ReflectUtils.forName(url.getServiceInterface());
    String globalValidator = url.getParameter("globalValidator");
    ValidatorFactory factory;
    if (globalValidator != null && globalValidator.length() > 0) {
    
        factory = Validation
                .byProvider((Class) ReflectUtils.forName(globalValidator))
                .configure().buildValidatorFactory();
    } else {
    
        factory = Validation.byProvider(HibernateValidator.class)
                .configure()
                .addProperty("hibernate.validator.fail_fast", "true")
                .buildValidatorFactory();
    }
    this.validator = factory.getValidator();
}

异常封装

参数校检错误时自定义错误信息,封装为RPCException

if (!violations.isEmpty()) {
   
    logger.error("Failed to validate service: " + clazz.getName()
            + ", method: " + methodName + ", cause: " + violations);

    String errorMsg = (violations.size() > 0) ? violations.iterator()
            .next().getMessage() : "参数校检错误";

    throw new RpcException(errorMsg, new ConstraintViolationException(
            "Failed to validate service: " + clazz.getName()
                    + ", method: " + methodName + ", cause: "
                    + violations, violations));
}

参考资料:

  1. Dubbo SPI
  2. 调用拦截扩展
  3. 验证拓展
相关文章
|
监控 API 开发者
深入理解微服务架构:构建可扩展的应用程序
【10月更文挑战第6天】深入理解微服务架构:构建可扩展的应用程序
377 0
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
518 2
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
1157 3
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
监控 持续交付 API
深入理解微服务架构:构建高效、可扩展的系统
【10月更文挑战第14天】深入理解微服务架构:构建高效、可扩展的系统
500 0
|
消息中间件 监控 API
理解微服务架构:构建灵活和可扩展的应用
【10月更文挑战第7天】理解微服务架构:构建灵活和可扩展的应用
|
消息中间件 监控 API
深入理解微服务架构:构建可扩展与灵活的应用
【10月更文挑战第7天】深入理解微服务架构:构建可扩展与灵活的应用
443 0
|
人工智能 数据可视化 JavaScript
颠覆开发效率!国内首个微服务编排框架Juggle开源啦!
Juggle是国内首个开源的微服务编排框架,专注于解决企业微服务进程中接口重复开发、系统对接复杂等问题。它提供零代码、低代码和AI增强功能,通过可视化拖拽快速组装简单API为复杂接口,支持多协议、多语言脚本和流程多版本管理。相比国外框架如Conductor,Juggle更贴合国内需求,具备高效开发、企业级可靠性及信创适配等优势,助力企业实现敏捷创新与数字化转型。
1407 0
颠覆开发效率!国内首个微服务编排框架Juggle开源啦!
|
Dubbo 应用服务中间件 Apache
Star 4w+,Apache Dubbo 3.3 全新发布,Triple X 领衔,开启微服务通信新时代
Star 4w+,Apache Dubbo 3.3 全新发布,Triple X 领衔,开启微服务通信新时代
371 0
|
监控 持续交付 API
深入理解微服务架构:构建高效、可扩展的系统
深入理解微服务架构:构建高效、可扩展的系统
485 4

热门文章

最新文章