单元测试中URI.getAuthority()始终返回null:80问题排查
问题根因
核心问题出在DefaultServiceInstance的使用方式上,和过滤逻辑、FilteringDiscoveryClient的核心流程无关:
- Spring Cloud Commons的
DefaultServiceInstance内部不会直接存储通过setUri()传入的URI对象,而是拆分存储scheme、host、port等独立字段,getUri()方法是运行时基于这些字段重新拼接生成URI。 - 空参构造的
DefaultServiceInstance实例,host默认值为null,port默认值为80。你直接调用setUri()传入自定义URI时,方法不会自动解析URI填充host、port、scheme字段。 - 你在setUp阶段调试看到URI正常,是因为当时查看的是自己手动创建的原始实例;而
SimpleDiscoveryClient初始化时会基于传入实例的host、port等字段重新构造服务实例对象,不会读取你手动set的URI值,最终返回到过滤器的实例URI拼接结果为http://null:80/xxx,调用getAuthority()自然返回null:80,导致过滤判断失效。
代码里还存在两个不影响当前报错但会留隐患的问题:
FilteringDiscoveryClient构造方法的参数校验有笔误:第二行Assert.notNull()第一个参数传的还是delegate,不是filter,传入null filter时校验不会生效,会触发空指针。- 就算URI配置正确,用
getAuthority()做判断也有兼容问题:如果服务使用非默认端口,authority会携带端口后缀(比如my.service.id.1:8080),equals判断会失效。
修复方案
1. 修正服务实例初始化方式
不要用空参构造+setUri的方式创建实例,改用全参构造或Builder模式,确保host、port字段被正确赋值:
// 全参构造示例 DefaultServiceInstance testInstance1_1 = new DefaultServiceInstance( "ins1_1", "my.service.id.1", "my.service.id.1", 80, false, Map.of() ); // Builder模式示例,可读性更好 DefaultServiceInstance testInstance1_2 = DefaultServiceInstance.builder() .serviceId("my.service.id.1") .host("my.service.id.1") .port(80) .build(); // 其余三个实例按相同逻辑初始化即可
2. 修正参数校验笔误
把构造方法中第二个断言的入参改为filter:
public FilteringDiscoveryClient(DiscoveryClient delegate, Predicate<ServiceInstance> filter) { Assert.notNull(delegate, "delegate must not be null"); Assert.notNull(filter, "filter must not be null"); // 原来这里错传了delegate this.delegate = delegate; this.filter = filter; }
3. 优化过滤判断逻辑
优先用ServiceInstance自带的getHost()方法做判断,避免URI解析带来的兼容问题:
FilteringDiscoveryClient client = new FilteringDiscoveryClient( mockClient, i -> !i.getHost().equals("my.service.id.1") );
修正后重新运行测试,实例URI会被正确构造,过滤逻辑正常生效,断言可顺利通过。
内容的提问来源于stack exchange,提问作者Pompompurin
相关产品推荐
相关产品推荐

