1. 程式人生 > >解決springcloud 中各服務之間呼叫外部依賴的clint api時,在除錯時不方便的問題

解決springcloud 中各服務之間呼叫外部依賴的clint api時,在除錯時不方便的問題

解決springcloud 中,各個服務中呼叫外部依賴的api,在除錯時不方便的問題

遮蔽外部依賴

Springcloud 開發中的同學肯定有過,程式碼中需要呼叫同項目中別的微服務的api介面,通常在專案中採用feign呼叫的方式,把應用啟動起來同時把自己相關的程式碼跑一遍。
通常有幾種做法:

  1. 本地把所有的服務都啟動起來。
  2. 把註冊中心換為開發環境,依賴開發環境的服務。
  3. 直接把程式碼推送到開發環境自測

看起來三種都可以,以前我也是這麼幹的。但還是有幾個小問題:

  1. 本地啟動有可能服務很多,全部起來電腦能不能撐住還兩說,萬一服務有問題就進行不下去了。
  2. 依賴開發環境的前提是網路打通,還有一個問題就是開發環境程式碼很不穩定很大可能會影響你的測試。
  3. 推送到開發環境應該是比較靠譜的方案,但如果想除錯只有日誌大法,沒有本地 debug 的效率高效。

那如何解決問題呢?既可以在本地除錯也不用啟動其他服務。

其實也可以利用單測的做法,把其他外部依賴 Mock 掉就行了。

大致的流程分

  1. SpringBoot 啟動之後在 Spring 中找出你需要遮蔽的那個 API 的 bean(通常情況下這個介面都是交給 Spring 管理的)。
  2. 手動從 bean 容器中刪除該 bean。
  3. 重新建立一個該 API 的物件,只不過是通過 Mock 出來的。
  4. 再手動註冊進 bean 容器中。

具體實踐

呼叫介面

// fegin呼叫的client
@Autowired
private ToolsClient toolsClient;

@RequestMapping(value = {"/query/cars"})
public HttpCommandResultWithData getProductSalesCarList
(@RequestBody SalesCarListCommand command){ ToBBusinessMessageCommand msgCommand = new ToBBusinessMessageCommand(); // fegin 呼叫的位置 HttpCommandResultWithData resultWithData = toolsClient.msgPushTools(msgCommand); logger.info("test result : {}", resultWithData); .... return result; }

如果按上述介面地址訪問測試,發現必定會報錯,因為ToolsClient所在的服務併為啟動

2018-10-23 11:30:59.560|ERROR|http-nio-8799-exec^呼叫介面[/qingqi/sellbusiness/query/cars]發生異常,message:[{}]com.netflix.hystrix.exception.HystrixRuntimeException: ToolsClient#msgPushTools(ToBBusinessMessageCommand) failed and no fallback available.

替換原有的 Bean

@Component
public class ToolsClientMockTest implements CommandLineRunner {

    protected static final Logger logger = LoggerFactory.getLogger(ToolsClientMockTest.class);

    @Autowired
    private ApplicationContext applicationContext;


    @Override
    public void run(String... strings) throws Exception {

        DefaultListableBeanFactory defaultListableBeanFactory =
                (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        ToolsClient toolsClient = defaultListableBeanFactory.getBean(ToolsClient.class);
        logger.info("===== Tools Client :{} =====", toolsClient.getClass());
        defaultListableBeanFactory.removeBeanDefinition(ToolsClient.class.getCanonicalName());

        ToolsClient toolsClientApi = PowerMockito.mock(ToolsClient.class, invocationOnMock -> {
            HttpCommandResultWithData result = new HttpCommandResultWithData().fillResult(ReturnCode.OK);
            Map<String, Object> map = new HashMap();
            map.put("datakey", "abc");
            map.put("datakey2", 2);
            result.setData(map);
            return result;
        });

        defaultListableBeanFactory.registerSingleton(ToolsClient.class.getCanonicalName(), toolsClientApi);

    }
}

測試

|2018-10-23 11:42:03.804|INFO|http-nio-8799-exec-test result : HttpCommandResultWithData{data={datakey=abc, datakey2=2}} CommonResult{resultCode=200, message='OK'}|

maven依賴

	<!-- https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito -->
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito</artifactId>
            <version>1.6.6</version>
        </dependency>

        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>1.6.6</version>
        </dependency>