0
点赞
收藏
分享

微信扫一扫

SpringCloud本地环境调用测试环境服务debug调试

深夜瞎琢磨 2021-09-25 阅读 214
spring cloud

使用spring cloud有一段时间了,相信很多使用spring cloud的时候都遇到过这样的苦恼,项目分成了多个微服务,有些业务需要互相依赖,第一就想到了使用feign调用,但是我们在开发debug时,需要在本机启动eureka server,还需要启动自己调试的方法依赖的其他微服务,一来二去,很可能调试方法依赖服务A,服务A又依赖B,我们就需要启动很多服务,以及各个服务所依赖的环境,导致调试非常的麻烦,接下来给大家介绍一种方法,可以不用启动这些环境,就可以调试问题的方案。

一、搭建测试环境

将项目中项目中所有服务搭建一个完整的环境,也可以直接使用测试环境,但是环境中的服务必须是可以使用互联网可以访问到,最好使用域名访问。

二、使用本地环境调用测试环境服务

要想让本地环境调用测试环境,需要了解eureka server中的服务是如何被各个微服务调用的,feign调用微服务时,使用了ribbon来做负载均衡,使用了Hystrix来做熔断,feign中的服务信息,来自于EurekaClient.fetchRegistry()方法可以取到所有eureka server上的服务,feign根据服务信息,获取到服务的ip(也可以是host,但是一般使用ip,host还要配置机器host列表)和端口以及结合在feign声明中的服务地址,拼成http请求的完整地址,再发送http请求实现调用微服务的目的。 那么关键就在于从Eureka中获取到的服务列表信息中的ip地址。以此提出以下两种解决方案:

  1. 在测试环境中的服务,直接在配置文件中,指定外网地址,这样本地服务就可以用外网地址进行服务访问了,但是这种方式,需要所有服务器开启相应外网端口,存在安全隐患,而且所有的服务间的调用都通过外网访问,也会影响速度,故不推荐。

  2. 下面介绍第二张情况,通过修改FeignConfig来完成远程微服务的调用,对测试环境无侵入,只在客户端设置,即可完成对测试环境中服务的调用,上面例子介绍了feign调用微服务时,需要拿到内网ip和端口以及服务地址,拼成完整的服务地址,那我们可以在拼接完整的服务地址时,将内网ip直接更换为域名,然后通过域名调用到微服务(前面已经说到,测试环境的服务都要可以通过外网访问到),这样就可以实现本地服务调用测试环境的服务,而不用在本地启动无数个依赖服务。为了不让本地环境注册到eureka上,将本地服务关闭注册到eureka,只设置从eureka拉取服务,下边给出配置例子:

eureka:
    debug: true   #自定义参数,开始本地环境通过eurake调用test环境中的服务,
                  #设置为true开启,开启后将register-with-eureka配置参数设置为false,防止test环境调用到本地的微服务出错
    debug-url: https://yuming.com #自定义参数, 测试环境注册微服务的真实访问路径,此配置适用于 同桌项目,其他项目根据情况配置
    client:
        fetch-registry: true
        register-with-eureka: false #本地使用时,将此属性设置为false,不会将本地服务注册到eurake上,但是本地服务可以从eurake上获取到服务信息
        service-url:
            defaultZone: http://89.234.306.43:8761/eureka/
package com.anjl.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.*;
import feign.codec.ErrorDecoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.feign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.stereotype.Component;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Map;

/**
 * @author anjl
 * 使用feign时,使用此配置
 */
@Configuration
@EnableConfigurationProperties
@Slf4j
public class FeignConfig {

    /**-----------以下配置是为了本地调试使用,测试和正式环境将${eureka.debug}设置为false即可----------**/

    @Value("${eureka.debug:false}")
    private Boolean debug;
    @Value("${eureka.debug-url:null}")
    private String debugUrl;

    public FeignConfig() {
    }

    @Bean
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) {
        return new LoadFeignBalancerFeignClient(new DefaultClient(null, null), cachingFactory, clientFactory);
    }


    class LoadFeignBalancerFeignClient implements Client {
        private LoadBalancerFeignClient loadBalancerFeignClient;

        public LoadFeignBalancerFeignClient(Client delegate, CachingSpringLoadBalancerFactory lbClientFactory, SpringClientFactory clientFactory) {
            loadBalancerFeignClient = new LoadBalancerFeignClient(delegate, lbClientFactory, clientFactory);
        }

        @Override
        public Response execute(Request request, Request.Options options) throws IOException {
            URI asUri = URI.create(request.url());
            String clientName = asUri.getHost();
            DefaultClient delegate = (DefaultClient) loadBalancerFeignClient.getDelegate();
            delegate.setClientName(clientName);
            return loadBalancerFeignClient.execute(request, options);
        }
    }


    class DefaultClient extends Client.Default implements Client {
        private String clientName;

        public void setClientName(String clientName) {
            this.clientName = clientName;
        }

        public DefaultClient(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
            super(sslContextFactory, hostnameVerifier);
        }

        @Override
        public Response execute(Request request, Request.Options options) throws IOException {
            if(debug){
                URI asUri = URI.create(request.url());
                String url = String.format("%s/%s%s?%s", debugUrl, clientName, asUri.getPath(), asUri.getQuery());
                request = Request.create(request.method(), url, request.headers(), request.body(), request.charset());
            }
            return super.execute(request, options);
        }
    }

    /**--------------------end--------------------------**/

    

    @Bean
    Logger.Level feignLoggerLevel() {
        //这里记录所有,根据实际情况选择合适的日志level
        return Logger.Level.FULL;
    }
}

package com.anjl.client;

import com.alibaba.fastjson.JSONObject;
import com.sunlands.zlcx.usercenter.config.OauthFeignConfig;
import com.sunlands.zlcx.usercenter.vo.feign.UsersGroupVO;
import com.sunlands.zlcx.usercenter.vo.response.BusinessResult;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@FeignClient(value = "group-api", configuration = OauthFeignConfig.class)
public interface GroupInfoService {

    /**
     * 根据用户id,查询群组信息
     * @param userId userId
     * @return Users
     */
    @RequestMapping(value = "/group/simple")
  List<Groups> getGroupInfoListByUserId(@RequestParam(value = "userId") Integer userId);
}

举报

相关推荐

0 条评论