在微服务架构中,服务注册中心是必不可少的组件,提供服务注册与管理的能力。目前使用ServiceComb服用中心的java微服务开发者,不仅需要写微服务业务代码,还要写客户端代码去调用ServiceCenter的openAPI。开发者首先需要熟悉ServiceCenter的openAPI文档,然后代码实现http客户端用于发起请求和接收响应,并绑定ServiceCenter配置参数,最后代码实现对服务中心API的调用,才能使用上ServiceCenter。为了简单化开发者使用ServiceCenter,ServiceCenter客户端实现了上述步骤。开发者只需要添加客户端jar包调用API就能轻松使用ServiceCenter,不需要过多关注openAPI文档、不需要写http客户端层代码。使用ServiceComb客户端,开发者可以轻松调用ServiceCenter,更专注于写微服务业务代码。
了解更多ServiceComb-Service-Center:https://docs.servicecomb.io/service-center/zh_CN/index.html
了解更多ServiceCenter客户端:https://github.com/apache/servicecomb-java-chassis/tree/master/clients/service-center-client
客户端发起请求和接收响应。客户端选择httpclient作为底层组件,用于实际发起请求和接收响应,并对请求和响应类进行了封装。代码中get方法对应发起GET请求,调用doRequest方法首先添加服务注册中心信息到封装过的httpRequest请求头部,再基于httpclient组件发起实际的http请求,最后将请求响应结果转化为封装过的httpResponse对象返回。
//make GET request
@Override
public HttpResponse get(HttpRequest request) throws IOException {
request.setMethod(HttpRequest.GET);
return doRequest(request);
}
......
//make http request with httpClient component
public HttpResponse doRequest(HttpRequest httpRequest) throws IOException {
//add cse-serviceregistry-client header to identify client
httpRequest.addHeader(HEADER_CONTENT_TYPE, "application/json");
httpRequest.addHeader(HEADER_USER_AGENT, "cse-serviceregistry-client/1.0.0");
if (globalHeaders != null) {
globalHeaders.forEach(httpRequest::addHeader);
}
//make http request
org.apache.http.HttpResponse response = httpClient.execute(httpRequest.getRealRequest());
int statusCode = response.getStatusLine().getStatusCode();
String messgae = response.getStatusLine().getReasonPhrase();
String context = EntityUtils.toString(response.getEntity(), "UTF-8");
return new HttpResponse(statusCode, messgae, context);
}
客户端支持定制化服务中心配置参数。代码中看到,客户端支持开发者定制服务中心IP,端口,项目名称,租户名称,导入TLSConfig和新增请求头,并通过客户端的Builder方法注入配置。TLSConfig为客户端TLS认证配置类,给客户端导入TLS证书配置,即可开启客户端双向认证模式。
/**
* Customized host, port, projectName, tenantName, TLSConf, headers and any one parameter can be null.
*/
public ServiceCenterClient(String host, int port, String projectName, String tenantName, TLSConfig tlsConfig,
Map<String, String> extraGlobalHeaders) {
HttpTransport httpTransport = HttpTransportFactory.getDefaultHttpTransport();
if (tlsConfig != null) {
httpTransport = new TLSHttpsTransport(tlsConfig);
}
httpTransport.addHeaders(extraGlobalHeaders);
//set configuration parameters
this.httpClient = new ServiceCenterRawClient.Builder()
.setHost(host)
.setPort(port)
.setProjectName(projectName)
.setTenantName(tenantName)
.setHttpTransport(httpTransport).build();
}
//service register
public String registerMicroserviceInstance(MicroserviceInstance instance, String serviceId) {
try {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
HttpResponse response = httpClient.postHttpRequest("/registry/microservices/" + serviceId + "/instances", null,
mapper.writeValueAsString(instance));
if (response.getStatusCode() == HttpStatus.SC_OK) {
return response.getContent();
} else {
throw new OperationException(
"register service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
+ "; content = " + response.getContent());
}
} catch (IOException e) {
throw new OperationException(
"register service instance fails", e);
}
}
//service discovery
public MicroserviceInstancesResponse getMicroserviceInstanceList(String serviceId) {
try {
HttpResponse response = httpClient
.getHttpRequest("/registry/microservices/" + serviceId + "/instances", null, null);
if (response.getStatusCode() == HttpStatus.SC_OK) {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(response.getContent(), MicroserviceInstancesResponse.class);
} else {
throw new OperationException(
"get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
+ "; content = " + response.getContent());
}
} catch (IOException e) {
throw new OperationException(
"get service instances list fails", e);
}
}
//heartBeats
public void sendHeartBeats(HeartbeatsRequest heartbeatsRequest) {
try {
ObjectMapper mapper = new ObjectMapper();
HttpResponse response = httpClient
.putHttpRequest("/registry/heartbeats", null, mapper.writeValueAsString(heartbeatsRequest));
if (response.getStatusCode() == HttpStatus.SC_OK) {
LOGGER.info("HEARTBEATS SUCCESS");
} else {
throw new OperationException(
"heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage()
+ "; content = " + response.getContent());
}
} catch (IOException e) {
throw new OperationException(
"heartbeats fails ", e);
}
}
public static void registerMicroservice(){
//new ServiceCenterClient object
ServiceCenterClient sc = new ServiceCenterClient();
//new Microservice object and setting properties and serviceName is necessary
Microservice microservice = new Microservice();
microservice.setServiceId("1111");
microservice.setServiceName("HelloServer");
//register microservice to service-center
sc.registerMicroservice(microservice);
//new MicroserviceInstance object and bind server IP and port
MicroserviceInstance instance = new MicroserviceInstance();
List<String> endPoints = new ArrayList<String>();
endPoints.add("rest://127.0.0.1:8080/");
instance.setEndpoints(endPoints);
//setting instance hostName, instanceId and hostName is necessary
instance.setHostName("test");
instance.setInstanceId("2222");
//register microservice instance to service-center
sc.registerMicroserviceInstance(instance,microservice.getServiceId());
//send a heartbeat every 30s
HeartbeatsRequest heartbeatsRequest = new HeartbeatsRequest("1111","2222");
while(true){
sc.sendHeartBeats(heartbeatsRequest);
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
查看service-center的UI显示如下,helloServer服务注册到服务中心成功,且有一个服务实例test。//find service instance
ServiceCenterClient sc = new ServiceCenterClient();
MicroserviceInstancesResponse instances = sc.getMicroserviceInstanceList("1111");
//get IP and port that service is listening on
URI endpointURIBuilder = new URIBuilder(instances.getInstances().get(0).getEndpoints().get(0)).build();
int port = endpointURIBuilder.getPort();
String host = endpointURIBuilder.getHost();
//call service
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.getForEntity("http://"+host+":"+port,String.class);
return result.getBody();
访问consumer端监听的8081端口,返回helloServer的响应结果“Hello Spring-Boot-ServiceCenter !”,consumer端通过ServiceComb服务注册中心调用provider端服务成功。