欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

dubbo參數(shù)校驗(yàn)ValidationFilter使用與說明

 更新時(shí)間:2025年10月20日 10:08:31   作者:hello_zzw  
本文介紹了Dubbo框架中Filter的核心功能和實(shí)現(xiàn)機(jī)制,Filter用于攔截RPC調(diào)用流程,支持自定義攔截邏輯,并通過SPI擴(kuò)展機(jī)制動(dòng)態(tài)加載,形成鏈?zhǔn)秸{(diào)用結(jié)構(gòu),文中還說明了內(nèi)置和自定義Filter的實(shí)現(xiàn)方式及ValidationFilter參數(shù)校驗(yàn)功能

org.apache.dubbo.rpc.Filter

核心功能

  • 攔截RPC調(diào)用流程

Filter是Dubbo框架中實(shí)現(xiàn)攔截邏輯的核心接口,作用于服務(wù)消費(fèi)者和提供者的作業(yè)鏈路,支持在方法調(diào)用前后插入自定義邏輯。如參數(shù)校驗(yàn)、異常處理、日志記錄等。

  • 擴(kuò)展性機(jī)制

Dubbo通過SPI擴(kuò)展機(jī)制動(dòng)態(tài)加載Filter實(shí)現(xiàn)類,構(gòu)建鏈?zhǔn)秸{(diào)用結(jié)構(gòu),每個(gè)Filter通過Invoke方案?jìng)鬟f調(diào)用上下文,最終執(zhí)行目標(biāo)方法。

實(shí)現(xiàn)機(jī)制

  • 責(zé)任鏈模式

Provider端Filter鏈在服務(wù)暴露時(shí)通過FilterChainBuilder#buildInvokerChain方法構(gòu)建,基于SPI配置按優(yōu)先級(jí)排序,形成多層攔截邏輯。

  • SPI加載規(guī)則

Filter實(shí)現(xiàn)類需要在META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter文件中聲明,并通過@Activate注解配置激活條件(如服務(wù)端/消費(fèi)端)

  • 動(dòng)態(tài)加載

Filter鏈在服務(wù)初始化階段動(dòng)態(tài)生成,通過ExtensionLoader加載所有激活的Filter實(shí)例,并按順序包裝成調(diào)用鏈。

常見內(nèi)置Filter實(shí)現(xiàn)

Filter名稱功能描述適用端
ExceptionFilter統(tǒng)一處理服務(wù)端異常,將非受檢異常封裝為RuntimeException返回客戶端Provider
ValidationFilter基于JSR303標(biāo)準(zhǔn)校驗(yàn)接口參數(shù)合法性Both
AccessLogFilter記錄服務(wù)調(diào)用日志,指定輸出到指定文件Provider
TimeoutFilter監(jiān)控方法執(zhí)行超時(shí),觸發(fā)超時(shí)中斷邏輯Provider
GenericFilter處理泛化調(diào)用的序列化與反序列化Both

自定義Filter實(shí)現(xiàn)步驟

  • 實(shí)現(xiàn)Filter接口
import com.alibaba.fastjson2.JSON;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// 使用@Activate注解指定Filter生效場(chǎng)景
// order屬性控制執(zhí)行順序,值越小,優(yōu)先級(jí)越高
@Activate(group = {CommonConstants.CONSUMER, CommonConstants.PROVIDER}, order = 10001)
public class CustomFilter implements Filter {
    private Logger logger = LoggerFactory.getLogger(CustomFilter.class);
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        logger.info("invoker invoked method {} {} {} {}",
                invocation.getMethodName(),
                JSON.toJSONString(invocation.getObjectAttachments()),
                invocation.getAttributes(),
                JSON.toJSONString(invocation.getArguments()));
        Result result = invoker.invoke(invocation);
        logger.info("invoker invoked result {}", JSON.toJSONString(result));
        return result;
    }
}
  • ‌聲明SPI擴(kuò)展‌

在resources/META-INF/dubbo目錄下創(chuàng)建配置文件org.apache.dubbo.rpc.Filter,添加自定義Filter類路徑:

consumer=com.doudou.demo.filter.CustomFilter

ValidationFilter

Dubbo的ValidationFilter是基于JSR303標(biāo)準(zhǔn)實(shí)現(xiàn)的參數(shù)校驗(yàn)組件,主要用于服務(wù)消費(fèi)者和服務(wù)提供者兩端,確保接口調(diào)用時(shí)參數(shù)的合法性。

核心特性

作用機(jī)制

  • 通過@Activate注解激活,默認(rèn)作用于消費(fèi)者和服務(wù)者兩端,執(zhí)行順序?yàn)?0000。
  • 在請(qǐng)求處理前攔截參數(shù),利用JSR303標(biāo)準(zhǔn)的注解進(jìn)行校驗(yàn),校驗(yàn)失敗時(shí)拋出異常中斷流程。

依賴配置

需要引入validation-apihibernate-validator依賴包

 <!-- Bean Validation API -->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<!-- Hibernate Validator實(shí)現(xiàn) -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.2.5.Final</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>jakarta.el</artifactId> <!-- 適配EL表達(dá)式 -->
    <version>5.0.0-M1</version>
</dependency>

使用

API

@Setter
@Getter
public class UserDTO implements Serializable {
    @NotBlank(message = "用戶名不能為空")
    private String username;

    @Min(value = 18, message = "年齡必須大于18歲")
    private Integer age;

    @Email(message = "郵箱格式不合法")
    private String email;
}
public class BaseResult<T> {
    // 處理是否正確結(jié)束
    private boolean success;
    // 異常編碼
    private Integer errorCode;
    // 異常描述
    private String errorMsg;
    // dubbo接口返回的結(jié)果
    private T data;
}    
public interface UserService {
    BaseResult<String> registerUser(UserDTO userDTO);
}

服務(wù)提供者

@DubboService(validation = "true")
public class UserServiceImpl implements UserService {

    @Override
    public BaseResult<String> registerUser(UserDTO userDTO) {
        return BaseResult.success("用戶注冊(cè)成功:" + userDTO.getUsername());
    }
}
public class ParameterVerificationResultFilter implements Filter {
    private Logger logger = LoggerFactory.getLogger(ParameterVerificationResultFilter.class);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Result result = invoker.invoke(invocation);
        // 處理出現(xiàn)異常
        if (result.hasException()) {
            Throwable exception = result.getException();
            // 是由參數(shù)校驗(yàn)失敗拋出的異常
            if (exception instanceof ConstraintViolationException) {
                List<String> errors = ((ConstraintViolationException) exception).getConstraintViolations().stream()
                        .map(v -> v.getPropertyPath() + ": " + v.getMessage())
                        .collect(Collectors.toList());
                logger.info("---------------2---------------");
                logger.error(errors.toString());
                logger.info("---------------3---------------");
                // 將錯(cuò)誤信息封裝到返回結(jié)果中
                return AsyncRpcResult.newDefaultAsyncResult(BaseResult.fail(400, errors.toString()), invocation);
            }
        }
        return result;
    }
}

META-INF/dubbo/org.apache.dubbo.rpc.Filter

# 參數(shù)校驗(yàn)過濾器
validation=org.apache.dubbo.validation.filter.ValidationFilter
# 校驗(yàn)結(jié)果處理過濾器
parameterVerification=com.doudou.filter.ParameterVerificationResultFilter

application.yml

dubbo:
	provider:
		filter: validation,parameterVerification

服務(wù)消費(fèi)方

@RestController
public class UserServiceController {
    @DubboReference(validation = "true")
    private UserService userService;

    @PostMapping("/test")
    public BaseResult<String> test(@RequestBody UserDTO userDTO) {
        return userService.registerUser(userDTO);
    }
}
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 處理RpcException異常
    @ExceptionHandler(RpcException.class)
    public ResponseEntity<BaseResult> handleValidationException(RpcException rpcException) {
        return ResponseEntity.badRequest().body(BaseResult.fail(403, rpcException.getLocalizedMessage()));
    }
}

源碼解析

org.apache.dubbo.validation.filter.ValidationFilter

public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
   // 判斷是否需要進(jìn)行參數(shù)驗(yàn)證
    if (needValidate(invoker.getUrl(), invocation.getMethodName())) {
        try {
            // 通過url中的validation屬性值獲取驗(yàn)證器
            Validator validator = validation.getValidator(invoker.getUrl());
            if (validator != null) {
                // 獲取到驗(yàn)證器時(shí),進(jìn)行參數(shù)驗(yàn)證
                validator.validate(
                        invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
            }
        } catch (RpcException e) {
            // RpcException 異常直接拋出
            throw e;
        } catch (Throwable t) {
            // 非RpcException,封裝到結(jié)果中返回
            return AsyncRpcResult.newDefaultAsyncResult(t, invocation);
        }
    }
    // 執(zhí)行下一個(gè)過濾器的處理
    return invoker.invoke(invocation);
}

 /**
  * 是否需要進(jìn)行參數(shù)驗(yàn)證
  */
 private boolean needValidate(URL url, String methodName) {
     return validation != null
             && !methodName.startsWith("$")
             && ConfigUtils.isNotEmpty(url.getMethodParameter(methodName, VALIDATION_KEY))
             && !"false".equalsIgnoreCase(url.getParameter(VALIDATION_KEY));
 }

org.apache.dubbo.validation.support.AbstractValidation

@Override
public Validator getValidator(URL url) {
    // 使用url作為存儲(chǔ)驗(yàn)證器map集合的的key
    String key = url.toFullString();
    // 從容器中獲取驗(yàn)證器
    Validator validator = validators.get(key);
    // 判斷驗(yàn)證器是否已經(jīng)存在
    if (validator == null) {
        // 如果不存在,則創(chuàng)建
        validators.put(key, createValidator(url));
        validator = validators.get(key);
    }
    return validator;
}

org.apache.dubbo.validation.support.jvalidation.JValidation

@Activate(onClass = "javax.validation.Validation")
public class JValidation extends AbstractValidation {

    /**
     * Return new instance of {@link JValidator}
     * @param url Valid URL instance
     * @return Instance of JValidator
     */
    @Override
    protected Validator createValidator(URL url) {
        // 創(chuàng)建一個(gè)Dubbo框架默認(rèn)的校驗(yàn)器
        return new JValidator(url);
    }
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java JSch遠(yuǎn)程執(zhí)行Shell命令的方法

    Java JSch遠(yuǎn)程執(zhí)行Shell命令的方法

    本文主要介紹了Java JSch遠(yuǎn)程執(zhí)行Shell命令,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • SpringBoot修改內(nèi)置tomcat版本的操作步驟

    SpringBoot修改內(nèi)置tomcat版本的操作步驟

    生產(chǎn)環(huán)境使用的外部部署Tomcat還是內(nèi)置Tomcat由于版本安全漏洞,往往需要升級(jí)到指定的安全版本,本文演示一下SpringBoot升級(jí)內(nèi)置的Tomcat版本,感興趣的小伙伴跟著小編一起來看看吧
    2024-07-07
  • Spring Framework常用面試題及答案匯總

    Spring Framework常用面試題及答案匯總

    這篇文章主要介紹了Spring Framework常用面試題及答案匯總,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • java根據(jù)當(dāng)前時(shí)間獲取yyyy-MM-dd?HH:mm:ss標(biāo)準(zhǔn)格式的時(shí)間代碼示例

    java根據(jù)當(dāng)前時(shí)間獲取yyyy-MM-dd?HH:mm:ss標(biāo)準(zhǔn)格式的時(shí)間代碼示例

    在Java中可以使用java.time包中的LocalDateTime類和DateTimeFormatter類來獲取并格式化當(dāng)前時(shí)間為yyyy-MM-dd?HH:mm:ss的格式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-10-10
  • 使用IntelliJ IDEA調(diào)式Stream流的方法步驟

    使用IntelliJ IDEA調(diào)式Stream流的方法步驟

    本文主要介紹了使用IntelliJ IDEA調(diào)式Stream流的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 關(guān)于Android觸摸事件分發(fā)的原理詳析

    關(guān)于Android觸摸事件分發(fā)的原理詳析

    觸摸事件分發(fā)機(jī)制一直以來都是Android中比較重要的一大塊,自定義view,各種復(fù)雜的自定義手勢(shì)交互都與觸摸事件分發(fā)機(jī)制關(guān)系密,下面這篇文章主要給大家介紹了關(guān)于Android觸摸事件分發(fā)原理的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • IDEA 通過腳本配置終端提示符樣式的方法

    IDEA 通過腳本配置終端提示符樣式的方法

    這篇文章給大家介紹IDEA通過腳本配置終端提示符樣式的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-08-08
  • SpringBoot整合kafka遇到的版本不對(duì)應(yīng)問題及解決

    SpringBoot整合kafka遇到的版本不對(duì)應(yīng)問題及解決

    這篇文章主要介紹了SpringBoot整合kafka遇到的版本不對(duì)應(yīng)問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java的四種引用方式

    Java的四種引用方式

    這篇文章主要介紹了Java的四種引用方式,Java的引用方式主要包括強(qiáng)引用、軟引用、弱引用、虛引用;下面文章便來詳細(xì)介紹這四種引用方式,需要的朋友可以參考一下
    2021-10-10
  • Flink流處理引擎零基礎(chǔ)速通之?dāng)?shù)據(jù)的抽取篇

    Flink流處理引擎零基礎(chǔ)速通之?dāng)?shù)據(jù)的抽取篇

    今天不分享基礎(chǔ)概念知識(shí)了,來分享一個(gè)馬上工作需要的場(chǎng)景,要做數(shù)據(jù)的抽取,不用kettle,想用flink。實(shí)際就是flink的sql、table層級(jí)的api
    2022-05-05

最新評(píng)論