实现自己的DiscoveryClient

需要做的:

  DiscoveryClient能提供那些服务的服务名列表

  返回指定服务对于的ServiceInstance列表

  返回DiscoveryClient的顺序

  返回HealthIndicator里显示的描述

实现LoadBalanceClient

  实现自己的ServiceList<T extends Server>

    Ribbon提供了AbstractServerList<T extends Server>

  提供一个配置类,声明ServerListBean 实例

pom引入

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
知识兔

 bootstartp.properties

spring.application.name=name-service
知识兔

application.yaml

server:
  port: 8080

#需要连接的服务
conns:
  services:
    - localhost:8088
知识兔

DiscoveryClient服务列表

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@ConfigurationProperties(prefix = "conns")
@Setter
@Slf4j
public class MyDiscoveryClient implements DiscoveryClient {

    public static final String SERVICE_ID = "conn-service";
    // waiter.services
    private List<String> services;

    @Override
    public String description() {
        return "DiscoveryClient that uses service.list from application.yml.";
    }

    @Override
    public List<ServiceInstance> getInstances(String serviceId) {
        if (!SERVICE_ID.equalsIgnoreCase(serviceId)) {
            return Collections.emptyList();
        }
        // 这里忽略了很多边界条件判断,认为就是 HOST:PORT 形式
        return services.stream()
                .map(s -> new DefaultServiceInstance(s,
                        SERVICE_ID,
                        s.split(":")[0],
                        Integer.parseInt(s.split(":")[1]),
                        false)).collect(Collectors.toList());
    }

    @Override
    public List<String> getServices() {
        return Collections.singletonList(SERVICE_ID);
    }
}
知识兔
ServerList
知识兔
import java.util.List;import java.util.stream.Collectors;public class MyServerList implements ServerList<Server> {    @Autowired    private  MyDiscoveryClient discoveryClient;    @Override    public List<Server> getInitialListOfServers() {        return getServers();    }    @Override    public List<Server> getUpdatedListOfServers() {        return getServers();    }    private List<Server>  getServers() {        return discoveryClient.getInstances(MyDiscoveryClient.SERVICE_ID).stream()                .map(i -> new Server(i.getHost(), i.getPort()))                .collect(Collectors.toList());    }}

开启:@EnableDiscoveryClient  //注册中心注册服务

注入bean

 @Bean     public DiscoveryClient myDiscovery(){        return new MyDiscoveryClient();     }     @Bean     public MyServerList   myServerList() {        return new MyServerList();     }    @Bean    public HttpComponentsClientHttpRequestFactory requestFactory() {        PoolingHttpClientConnectionManager connectionManager =                new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);        connectionManager.setMaxTotal(200);        connectionManager.setDefaultMaxPerRoute(20);        CloseableHttpClient httpClient = HttpClients.custom()                .setConnectionManager(connectionManager)                .evictIdleConnections(30, TimeUnit.SECONDS)                .disableAutomaticRetries()                // 有 Keep-Alive 认里面的值,没有的话永久有效                //.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)                // 换成自定义的                .setKeepAliveStrategy(new CustomConnectionKeepAliveStrategy())                .build();        HttpComponentsClientHttpRequestFactory requestFactory =                new HttpComponentsClientHttpRequestFactory(httpClient);        return requestFactory;    }    @LoadBalanced    @Bean    public RestTemplate restTemplate(RestTemplateBuilder builder) {        return builder                .setConnectTimeout(Duration.ofMillis(100))                .setReadTimeout(Duration.ofMillis(500))                .requestFactory(this::requestFactory)                .build();    }
import org.apache.commons.lang3.StringUtils;import org.apache.commons.lang3.math.NumberUtils;import org.apache.http.HttpResponse;import org.apache.http.conn.ConnectionKeepAliveStrategy;import org.apache.http.protocol.HTTP;import org.apache.http.protocol.HttpContext;import java.util.Arrays;public class CustomConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy {    private final long DEFAULT_SECONDS = 30;    @Override    public long getKeepAliveDuration(HttpResponse response, HttpContext context) {        return Arrays.asList(response.getHeaders(HTTP.CONN_KEEP_ALIVE))                .stream()                .filter(h -> StringUtils.equalsIgnoreCase(h.getName(), "timeout")                        && StringUtils.isNumeric(h.getValue()))                .findFirst()                .map(h -> NumberUtils.toLong(h.getValue(), DEFAULT_SECONDS))                .orElse(DEFAULT_SECONDS) * 1000;    }}

开启localhost:8088服务

测试:

  

import com.example.discovery.model.TechnologyType;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.core.ParameterizedTypeReference;import org.springframework.http.HttpMethod;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Component;import org.springframework.web.client.RestTemplate;import java.util.List;@Component@Slf4jpublic class CustomerRunner implements ApplicationRunner {    @Autowired    private RestTemplate  restTemplate;    @Override    public void run(ApplicationArguments args) throws Exception {        showServiceInstances();    }    private void showServiceInstances() {        ParameterizedTypeReference<List<TechnologyType>> ptr =            new ParameterizedTypeReference<List<TechnologyType>>() {};        ResponseEntity<List<TechnologyType>> list = restTemplate                .exchange("http://waiter-service/tech/", HttpMethod.GET, null, ptr);        list.getBody().forEach(t -> log.info("technology: {}", t));    }}

运行结果

  

TechnologyType{techTypeId='1', techTypeName='先进医疗/康复设备', techTypeDesc='', techCreateDate=Wed Sep 04 14:56:38 CST 2019}TechnologyType{techTypeId='2', techTypeName='大数据', techTypeDesc='null', techCreateDate=Thu Aug 29 10:47:47 CST 2019}
计算机