当前位置: 首页 > news >正文

从可插拔拦截器出发:自定义、注入 Spring Boot、到生效路径的完整实践(Demo 版)

1. 拦截器要解决什么问题?

  • 把签名、打点、鉴权、灰度、审计等横切逻辑从业务请求中抽离;

  • 低侵入接入任意 OkHttpClient;

  • 能通过运行时配置(如开关、密钥、目标地址等)动态生效;

  • 支持“是否命中某个条件才生效”的灰度能力。


2. 自定义一个 OkHttp Interceptor

下方仅为示例:拦截器在命中某个“特征”时,将请求“包一层”再转发;未命中则直通

public final class DemoInterceptor implements Interceptor {
​private final DemoRuntimeSwitch runtime; // 运行时开关 & 配置
​public DemoInterceptor(DemoRuntimeSwitch runtime) {this.runtime = runtime;}
​@Overridepublic Response intercept(Chain chain) throws IOException {Request original = chain.request();
​// 1) 未开启或配置不完整:放行if (!runtime.isOn() || !runtime.isConfigReady()) {return chain.proceed(original);}
​// 2) 命中某个触发条件(Demo:URL 上带 trigger=true)boolean hit = "true".equalsIgnoreCase(original.url().queryParameter("trigger"));if (!hit) return chain.proceed(original);
​// 3) 包装:示意将原请求信息转成一个 JSON 文本String wrapped = DemoJson.wrap(original); // {method, path, headers, query, body}
​// 4) 生成一个示意“签名”字符串(真实场景请用更安全算法与协议)String sign = DemoSign.simple(runtime.getAppKey(), runtime.getSecret(), wrapped);
​// 5) 构造“第二跳”请求(Demo:POST 表单提交到 runtime.getSecondHopUrl())Request secondHop = new Request.Builder().url(runtime.getSecondHopUrl()).post(new FormBody.Builder().add("appKey", runtime.getAppKey()).add("payload", wrapped).add("sign", sign).build()).build();
​try {return chain.proceed(secondHop);} catch (Exception ex) {// 6) 兜底:返回一个 Demo 错误响应(生产可返回统一错误结构)return DemoResponse.errorJson(500, "second-hop failed: " + ex.getMessage());}}
}

要点回顾:

  • 触发条件外置,真实可换成 token、Header、白名单等;

  • 直通优先:未命中一律放行,降低对主链路影响;

  • 二跳独立配置:URL、超时、重试策略等在配置中统一管理。


3. 运行时配置开关(Demo)

//只展示结构与意图
public final class DemoRuntimeSwitch {private volatile boolean on;private volatile String appKey;private volatile String secret;private volatile String secondHopUrl;
​public boolean isOn() { return on; }public boolean isConfigReady() {return appKey != null && !appKey.isEmpty() &&secret != null && !secret.isEmpty() &&secondHopUrl != null && !secondHopUrl.isEmpty();}
​// 可由配置中心/管理接口更新public String getAppKey() { return appKey; }public String getSecret() { return secret; }public String getSecondHopUrl() { return secondHopUrl; }
}
  • 实际可用 AtomicReference 持有完整配置快照;

  • 更新方式可来自配置中心/Redis/管理接口,做到秒级生效

  • 配置校验应集中在一个地方(例如 normalizeAndValidate())。


4. 在 Spring Boot 中注入拦截器(Demo)

方式 A:直接注册为 Bean

@Configuration
public class DemoInterceptorConfig {
​@Beanpublic DemoRuntimeSwitch demoRuntimeSwitch() { return new DemoRuntimeSwitch(); }
​@Beanpublic Interceptor demoInterceptor(DemoRuntimeSwitch runtime) {return new DemoInterceptor(runtime);}
}

方式 B:自动收集所有拦截器,再统一挂载(可插拔)

// 一个简单的“桥”,把容器中的拦截器收集起来,统一挂载到 OkHttp
public final class DemoInterceptorBridge {private static final CopyOnWriteArrayList<Interceptor> LIST = new CopyOnWriteArrayList<>();public static void registerAll(Collection<Interceptor> its) { LIST.addAll(its); }public static void attachAll(OkHttpClient.Builder b){for (Interceptor it : LIST) {boolean exists = b.interceptors().stream().anyMatch(x -> x.getClass().getName().equals(it.getClass().getName()));if (!exists) b.addInterceptor(it);}}
}
​
@Configuration
public class DemoAutoCollectConfig {@Beanpublic ApplicationRunner collectInterceptors(List<Interceptor> interceptors){return args -> DemoInterceptorBridge.registerAll(interceptors);}
}

这样,业务侧无需感知有哪些拦截器,统一通过“桥”完成补挂,真正做到可插拔


5. 让拦截器在 OkHttp 中真正生效(Demo)

public final class DemoOkHttpFactory {public static OkHttpClient newClient(){OkHttpClient.Builder b = new OkHttpClient.Builder().connectTimeout(Duration.ofSeconds(5)).readTimeout(Duration.ofSeconds(10));
​// 统一补挂所有已注册的拦截器DemoInterceptorBridge.attachAll(b);return b.build();}
}

生效路径

  1. Spring 启动:扫描并注册所有 Interceptor Bean → 交给 DemoInterceptorBridge

  2. 构建客户端:使用 DemoOkHttpFactory.newClient() 获取 OkHttpClient

  3. 发起请求:OkHttp 按拦截器顺序依次调用 intercept() → 命中条件的拦截器执行逻辑,否则放行;

  4. 运行期:通过 DemoRuntimeSwitch 更新开关与参数,无重启生效。


6. 端到端流程示意


7. 最佳实践

  • 直通优先:非命中条件一律放行,降低链路抖动;

  • 独立配置:把“是否启用”“目标地址”“签名策略”都放到运行时配置中;

  • 安全策略:签名/加密算法做成可替换的策略接口;敏感字段统一脱敏;

  • 顺序管理:有依赖关系的拦截器(例如“鉴权 → 访问日志”)要明确注册顺序;

  • 测试清单:命中/未命中、配置缺失、远端超时/5xx、请求体不可重复读取等场景;

  • 可观测:埋点 traceId、耗时、命中率、错误码分布,日志注意截断与采样。


8. Demo 模板

//自定义拦截器骨架(最小实现)public class MyDemoInterceptor implements Interceptor {@Override public Response intercept(Chain chain) throws IOException {Request req = chain.request();// 前置:校验/打点/改写(按需)Response resp = chain.proceed(req);// 后置:统计/日志(按需)return resp;}
}
//Spring 注入 + 统一补挂@Configuration
public class MyDemoOkHttpConfig {@Bean public Interceptor myDemoInterceptor(){ return new MyDemoInterceptor(); }@Bean public OkHttpClient httpClient(){OkHttpClient.Builder b = new OkHttpClient.Builder();DemoInterceptorBridge.attachAll(b);return b.build();}
}
//运行时开关(示意)public final class MySwitch {private final AtomicBoolean on = new AtomicBoolean(false);public boolean isOn(){ return on.get(); }public void setOn(boolean v){ on.set(v); }
}

http://www.dtcms.com/a/479570.html

相关文章:

  • 网站域名区别吗常州seo外包公司
  • [GO]Go语言泛型详解
  • 网站设计的汕头公司咨询公司名称
  • 成都网站建设木子网络网站按条件显示广告图片
  • MySQL----存储过程和存储函数
  • python - 第三天
  • 可信赖的网站建设案例wordpress垂直分页导航插件
  • led外贸网站制作建设网站中期要做什么
  • H3C NQA+track 实现 双链路主备切换
  • 域名网站排名如何免费自做企业网站
  • 深圳龙岗做网站wordpress 用户 权限
  • 做毕业设计免费网站建设游民星空是谁做的网站
  • 合肥高端网站建设设计公司哪家好下载手机商城app下载安装
  • 35岁,挺好,慢慢来,比较快
  • Python爬虫实战:获取同花顺技术选股数据并做分析
  • 四平做网站佳业网络wordpress电商平台搭建
  • 10、Python流程控制-条件判断
  • 广州祥云平台网站建设如何建一个微信公众号
  • 详解AVL树旋转操作实现
  • 宁波网站推广外包服务湖南网络公司网站建设
  • Appsflyer Web2App :两种方式全解析
  • Linux之环境变量
  • 爱站网挖掘关键词厚昌营销网站建设
  • 大型国有企业网站建设wordpress固定链接显示404
  • 料神wordpress建站教程windows优化大师是什么
  • CCF-GESP 等级考试 2025年9月认证C++二级真题解析
  • 广州公司网站长春新增2个高风险地区
  • wordpress建手机网站吗wordpress 花瓣网
  • 2025深圳国际全触与显示展影响力如何?本次会展有那些亮点?
  • 网站开发有哪些软件有哪些wordpress 获取文章的标签