实现自己的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
@Slf4j
public 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}
posted @ 2019-10-09 11:01  兮夜里人来人往  阅读(1012)  评论(1编辑  收藏  举报