微服务框架(十一)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天】深入理解微服务架构:构建可扩展的应用程序
297 0
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
428 2
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
监控 持续交付 API
深入理解微服务架构:构建高效、可扩展的系统
【10月更文挑战第14天】深入理解微服务架构:构建高效、可扩展的系统
426 0
|
消息中间件 监控 API
理解微服务架构:构建灵活和可扩展的应用
【10月更文挑战第7天】理解微服务架构:构建灵活和可扩展的应用
|
消息中间件 监控 API
深入理解微服务架构:构建可扩展与灵活的应用
【10月更文挑战第7天】深入理解微服务架构:构建可扩展与灵活的应用
374 0
|
Dubbo 应用服务中间件 Apache
Star 4w+,Apache Dubbo 3.3 全新发布,Triple X 领衔,开启微服务通信新时代
在 Apache Dubbo 突破 4w Star 之际,Apache Dubbo 团队正式宣布,Dubbo 3.3 正式发布!作为全球领先的开源微服务框架,Dubbo 一直致力于为开发者提供高性能、可扩展且灵活的分布式服务解决方案。此次发布的 Dubbo 3.3,通过 Triple X 的全新升级,突破了以往局限,实现了对南北向与东西向流量的全面支持,并提升了对云原生架构的友好性。
546 113
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——拦截自定义异常
本文介绍了在实际项目中如何拦截自定义异常。首先,通过定义异常信息枚举类 `BusinessMsgEnum`,统一管理业务异常的代码和消息。接着,创建自定义业务异常类 `BusinessErrorException`,并在其构造方法中传入枚举类以实现异常信息的封装。最后,利用 `GlobalExceptionHandler` 拦截并处理自定义异常,返回标准的 JSON 响应格式。文章还提供了示例代码和测试方法,展示了全局异常处理在 Spring Boot 项目中的应用价值。
643 0
|
Dubbo 应用服务中间件 Apache
Star 4w+,Apache Dubbo 3.3 全新发布,Triple X 领衔,开启微服务通信新时代
Star 4w+,Apache Dubbo 3.3 全新发布,Triple X 领衔,开启微服务通信新时代
255 0
|
监控 持续交付 API
深入理解微服务架构:构建高效、可扩展的系统
深入理解微服务架构:构建高效、可扩展的系统
364 4

热门文章

最新文章