須要作的:java
DiscoveryClient能提供那些服務的服務名列表web
返回指定服務對於的ServiceInstance列表spring
返回DiscoveryClient的順序apache
返回HealthIndicator裏顯示的描述app
實現LoadBalanceClientide
實現本身的ServiceList<T extends Server>測試
Ribbon提供了AbstractServerList<T extends Server>大數據
提供一個配置類,聲明ServerListBean 實例
ui
pom引入this
<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}