Nacos源码:@ExtractorManager.Extractor

本文收录于专栏 Nacos
推荐阅读:Nacos 架构 & 原理


前言

在这里插入图片描述
阅读Nacos源码时,经常看到 Controller 中有@ExtractorManager.Extractor这么一个注解。那么它的作用是什么?

一、@ExtractorManager.Extractor

Module: core

我们来逐步看下源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Extractor {
    Class<? extends AbstractHttpParamExtractor> httpExtractor() default DefaultHttpExtractor.class;
    Class<? extends AbstractRpcParamExtractor> rpcExtractor() default DefaultGrpcExtractor.class;
}
  • 这段代码定义了Extractor注解,允许在类或方法上配置自定义的参数提取器。
  • @Target 指定了该注解可以应用于类型(类、接口等)或方法。
  • @Retention 表明注解在运行时可用。
  • @Documented 表示该注解可以包含在 javadoc 中。
  • httpExtractorrpcExtractor 分别指定了默认的 HTTP 和 gRPC 参数提取器类。
public static class DefaultHttpExtractor extends AbstractHttpParamExtractor {
    @Override
    public List<ParamInfo> extractParam(HttpServletRequest params) {
        return Collections.emptyList();
    }
}

public static class DefaultGrpcExtractor extends AbstractRpcParamExtractor {
    @Override
    public List<ParamInfo> extractParam(Request request) {
        return Collections.emptyList();
    }
}
  • DefaultHttpExtractorDefaultGrpcExtractorhttpExtractorrpcExtractor的默认参数提取器。
  • 默认不提取,直接返回空集合。

AbstractHttpParamExtractorAbstractRpcParamExtractorParamExtractor的抽象实现,ParamExtractor中只有一个方法,定义extractParam方法提取参数,这里不做展开。

private static HashMap<Class<? extends AbstractRpcParamExtractor>, AbstractRpcParamExtractor> rpcManager = new HashMap<>();
private static HashMap<Class<? extends AbstractHttpParamExtractor>, AbstractHttpParamExtractor> httpManager = new HashMap<>();
static {
    NacosServiceLoader.load(AbstractHttpParamExtractor.class).forEach(checker -> {
        httpManager.put(checker.getClass(), checker);
    });
    NacosServiceLoader.load(AbstractRpcParamExtractor.class).forEach(checker -> {
        rpcManager.put(checker.getClass(), checker);
    });
}
  • 这两个静态哈希表分别用于存储和管理 gRPC 和 HTTP 参数提取器实例。
  • 通过类类型作为键,实例作为值,以便快速检索和避免重复创建。
  • 静态代码块在类加载时执行。
  • NacosServiceLoader.load 用于加载所有实现了 AbstractHttpParamExtractorAbstractRpcParamExtractor 的类,并将它们的实例添加到相应的哈希表中。
public static AbstractRpcParamExtractor getRpcExtractor(Extractor extractor) {
    return rpcManager.computeIfAbsent(extractor.rpcExtractor(), (key) -> new DefaultGrpcExtractor());
}

public static AbstractHttpParamExtractor getHttpExtractor(Extractor extractor) {
    return httpManager.computeIfAbsent(extractor.httpExtractor(), (key) -> new DefaultHttpExtractor());
}
  • 这两个方法根据 Extractor 注解中的配置,获取对应的参数提取器实例。

总结

ExtractorManager 类的主要用途是为不同类型的请求(HTTP 和 gRPC)动态提供合适的参数提取器。通过注解方式,调用者可以灵活地在不同的处理器方法或类上指定不同的提取器(class),增强了代码的可配置性和可扩展性。

二、CheckConfiguration

@Configuration
public class CheckConfiguration {
    
    @Bean
    public FilterRegistrationBean<ParamCheckerFilter> checkerFilterRegistration(ParamCheckerFilter checkerFilter) {
        FilterRegistrationBean<ParamCheckerFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(checkerFilter);
        registration.addUrlPatterns("/*");
        registration.setName("checkerFilter");
        registration.setOrder(8);
        return registration;
    }
    
    @Bean
    public ParamCheckerFilter checkerFilter(ControllerMethodsCache methodsCache) {
        return new ParamCheckerFilter(methodsCache);
    }
}
  • checkerFilterRegistration 方法
    • 这是一个 @Bean 方法,用于创建并注册 ParamCheckerFilterFilterRegistrationBean
    • FilterRegistrationBean:这是 Spring 提供的一个类,用于在应用程序中注册过滤器
  • checkerFilter 方法
    • 这是另一个 @Bean 方法,用于创建 ParamCheckerFilter 实例。
    • 参数 ControllerMethodsCache methodsCache(不做展开):这是一个依赖注入的对象,提供对控制器方法的缓存支持。

三、ParamCheckerFilter

我们看下这个参数校验过滤器中的核心代码:

//从方法中获取Extractor
ExtractorManager.Extractor extractor = method.getAnnotation(ExtractorManager.Extractor.class);
if (extractor == null) {
	//如果方法上没有,尝试从类上获取
    extractor = method.getDeclaringClass().getAnnotation(ExtractorManager.Extractor.class);
    if (extractor == null) {
        chain.doFilter(request, response);
        return;
    }
}
//ExtractorManager中获取@ExtractorManager.Extractor中指定的提取器实现
AbstractHttpParamExtractor httpParamExtractor = ExtractorManager.getHttpExtractor(extractor);
//参数提取
List<ParamInfo> paramInfoList = httpParamExtractor.extractParam(req);
ParamCheckerManager paramCheckerManager = ParamCheckerManager.getInstance();
//获取参数校验实现类
AbstractParamChecker paramChecker = paramCheckerManager.getParamChecker(ServerParamCheckConfig.getInstance().getActiveParamChecker());
//执行参数校验
ParamCheckResponse paramCheckResponse = paramChecker.checkParamInfoList(paramInfoList);
if (paramCheckResponse.isSuccess()) {
    chain.doFilter(req, resp);
} else {
    Loggers.CONTROL.info("Param check invalid,{},url:{}", paramCheckResponse.getMessage(), req.getRequestURI());
    generate400Response(resp, paramCheckResponse.getMessage());
}


总结

  • ExtractorManager
    • 管理了不同类型的参数提取器 (AbstractHttpParamExtractorAbstractRpcParamExtractor) 的实例化和获取。
    • 使用了自定义的 @Extractor 注解来指定类或方法应使用的提取器,支持灵活配置。
    • 通过静态初始化块和 NacosServiceLoader,它加载并管理所有可用的提取器实现,避免了手动实例化和配置。
  • ParamCheckerFilter
    • ParamCheckerFilter 是一个实现了 Filter 接口的过滤器类,用于拦截 HTTP 请求并进行参数校验。
    • 它依赖于 ControllerMethodsCache 类来获取请求方法,以及使用 ExtractorManagerParamCheckerManager 来选择和应用合适的参数提取器和校验器。
    • 根据配置,它可以启用或禁用参数校验功能,确保在必要时进行有效的参数验证。
    • 当参数校验失败时,它能够生成 HTTP 400 响应,并记录相关的错误日志信息。
  • CheckConfiguration
    • CheckConfiguration 是一个 Spring 配置类,负责将 ParamCheckerFilter 注册为 Spring Bean,并设置其在过滤器链中的顺序和作用路径。
    • 使用了 FilterRegistrationBean 来配置和注册过滤器,确保其在应用中正确地拦截和处理 HTTP 请求。
  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高级摸鱼工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值