【微服务本地调试】

微服务远程调用-本地调试

  • 项目背景
  • 现状
  • 期望效果
  • 步骤

项目背景

注册中心使用了Nacos,框架是SpringCloud,远程调用基于Feign实现。

现状

当服务之间需要联调时,只能将本地启动的服务注册至nacos,修改权重分流至本地。缺点是不仅不能调试服务执行过程中调用到的其他服务,还会污染测试环境。

期望效果

当本地服务启动发生远程调用时,无需注册至注册中心,可根据bootstrap.yml配置中的服务列表,请求至本地的指定服务;若无配置于bootstrap.yml服务列表的服务,则走默认从注册中心的服务列表获取。以分流指定服务的流量至本地,实现本地联调。

步骤

  1. bootstrap.yml #自定义服务配置列表格式
ribbon:
  listOfServers:
    - { host: "127.0.0.1", port: "8081", name: "service-a" }
    - { host: "127.0.0.1", port: "8082", name: "service-b" }
  1. RibbonServerList #服务配置列表接口对象
public class RibbonServerList {

    private String name;

    private String host;

    private int port;
	//省略GET SET
}
  1. RibbonConfigurationProperties 使用ConfigurationProperties映射服务配置列表
@Component
@ConfigurationProperties(prefix = "ribbon")
public class RibbonConfigurationProperties {

    @Value("${spring.profiles.active}")
    private String env;
    
    private List<RibbonServerList> listOfServers;
    //省略GET SET
}
  1. RibbonLocalServiceRule #分流至本地的自定义策略
public class RibbonLocalServiceRule extends AbstractLoadBalancerRule {

    private static Logger log = LoggerFactory.getLogger(RibbonLocalServiceRule.class);

    @Autowired
    RibbonConfigurationProperties ribbonConfigurationProperties;

    @PostConstruct
    public void init(){
        if(ribbonConfigurationProperties.getEnv().equals("prod")){
            throw new RuntimeException("请勿在正式环境使用此配置!");
        }
        var env = ribbonConfigurationProperties.getEnv();
        //此处listofServers当配置文件未声明listofServers,会报null异常,get方法上null -> new
        var localSever = ribbonConfigurationProperties.getListOfServers();
        log.info("本地调试,环境: " + env);
        log.info("本地调试服务列表:");
        localSever.forEach(s -> {
            log.info("== " + s.getName()  + ": " + s.getHost()+":"+s.getPort() + " ==");
        });
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {}

    @Override
    public Server choose(Object key) {
    	//当profile为test(测试环境)时,则走默认策略;起保险作用。
        if(ribbonConfigurationProperties.getEnv().equals("test")){
            return chooseEnvServer(getLoadBalancer());
        }
        return chooseLocalServer(getLoadBalancer());
    }

    public Server chooseEnvServer(ILoadBalancer lb){
        return lb.getReachableServers().stream().findAny().orElseThrow(() -> new RuntimeException("No up servers available from load balancer: " + lb));
    }

    public Server chooseLocalServer(ILoadBalancer lb){
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }
        var dynamicLoadBalancer = (DynamicServerListLoadBalancer)lb;
        String serviceName = dynamicLoadBalancer.getName();
        var localServers = ribbonConfigurationProperties.getListOfServers();

        if(localServers.isEmpty()){
            return this.chooseEnvServer(lb);
        } else {
            List<RibbonServerList> currentServiceServers = ribbonConfigurationProperties.getListOfServers().stream().filter(s -> s.getName().equals(serviceName)).collect(Collectors.toList());
            Optional<RibbonServerList> localServerOptional = currentServiceServers.stream().findAny();
            if(localServerOptional.isPresent()){
                return new Server(localServerOptional.get().getHost(),localServerOptional.get().getPort());
            }
            return this.chooseEnvServer(lb);
        }
    }
}
  1. RibbonLocalServiceRuleConfig 声明为未配置的Bean
public class RibbonLocalServiceRuleConfig {

    @Bean
    @Scope(value="prototype")  //注意此处应为多实例,不然获取的ILoadBalancer永远为上次请求的配置
    @Profile("dev")            //保险作用,dev为本地开发时生效bean
    public IRule localServiceRule() {
        // 指定策略:我们自定义的策略
        return new RibbonLocalServiceRule();
    }
}

最后一步,于BootstrapApplication引入此RibbonLocalServiceRuleConfig,当需要本地调试时则引入。

@EnableFeignClients(PACKAGE)
@EnableDiscoveryClient
@SpringBootApplication(scanBasePackages = PACKAGE)
@Import(RibbonLocalServiceRuleConfig.class)
public class BootstrapApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootstrapApplication.class, args);
    }
}

你可能感兴趣的:(微服务,java,spring)