Tôi đang sử dụng RestTemplate
làm HttpClient
để thực thi URL và máy chủ sẽ trả lại chuỗi json làm phản hồi. Khách hàng sẽ gọi cho thư viện này bằng cách đi qua đối tượng DataKey
có userId
trong đó.Làm thế nào để làm theo nguyên tắc Trách nhiệm duy nhất trong thực thi HttpClient của tôi?
- Sử dụng cho
userId
, tôi sẽ tìm hiểu các máy mà tôi có thể nhấn để lấy dữ liệu và sau đó lưu trữ các loại máy mộtLinkedList
, để tôi có thể thực hiện chúng liên tục là gì. - Sau đó tôi sẽ kiểm tra xem tên máy chủ đầu tiên có nằm trong danh sách chặn hay không. Nếu nó không có trong danh sách chặn, sau đó tôi sẽ tạo một URL với tên máy chủ đầu tiên trong danh sách và thực hiện nó và nếu phản hồi thành công thì trả về phản hồi. Nhưng giả sử rằng tên máy chủ đầu tiên nằm trong danh sách chặn, thì tôi sẽ cố gắng lấy tên máy chủ thứ hai trong danh sách và tạo url và thực thi nó, vì vậy về cơ bản, đầu tiên tìm thấy tên máy chủ không có trong danh sách chặn trước khi thực hiện URL.
- Bây giờ, giả sử nếu chúng ta chọn tên máy chủ đầu tiên không có trong danh sách khối và thực thi URL và máy chủ nào đó không hoạt động, thì tôi sẽ thực thi tên máy chủ thứ hai trong danh sách và tiếp tục thực hiện điều này cho đến khi bạn nhận được phản ứng thành công. Nhưng hãy đảm bảo rằng chúng cũng không nằm trong danh sách chặn vì vậy chúng tôi cần theo dõi ở trên.
- Nếu tất cả các máy chủ đều nằm trong danh sách chặn, thì tôi có thể chỉ cần đăng nhập và trả lại lỗi mà dịch vụ không khả dụng.
Dưới đây là lớp DataClient sẽ được khách hàng gọi và họ sẽ chuyển DataKey
đối tượng đến phương thức getData
.
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
private ExecutorService service = Executors.newFixedThreadPool(15);
public Future<DataResponse> getData(DataKey key) {
DataExecutorTask task = new DataExecutorTask(key, restTemplate);
Future<DataResponse> future = service.submit(task);
return future;
}
}
Dưới đây là lớp DataExecutorTask tôi:
public class DataExecutorTask implements Callable<DataResponse> {
private DataKey key;
private RestTemplate restTemplate;
public DataExecutorTask(DataKey key, RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.key = key;
}
@Override
public DataResponse call() {
DataResponse dataResponse = null;
ResponseEntity<String> response = null;
MappingsHolder mappings = ShardMappings.getMappings(key.getTypeOfFlow());
// given a userId, find all the hostnames
// it can also have four hostname or one hostname or six hostname as well in the list
List<String> hostnames = mappings.getListOfHostnames(key.getUserId());
for (String hostname : hostnames) {
// If host name is null or host name is in local block list, skip sending request to this host
if (ClientUtils.isEmpty(hostname) || ShardMappings.isBlockHost(hostname)) {
continue;
}
try {
String url = generateURL(hostname);
response = restTemplate.exchange(url, HttpMethod.GET, key.getEntity(), String.class);
if (response.getStatusCode() == HttpStatus.NO_CONTENT) {
dataResponse = new DataResponse(response.getBody(), DataErrorEnum.NO_CONTENT,
DataStatusEnum.SUCCESS);
} else {
dataResponse = new DataResponse(response.getBody(), DataErrorEnum.OK,
DataStatusEnum.SUCCESS);
}
break;
// below codes are duplicated looks like
} catch (HttpClientErrorException ex) {
HttpStatusCodeException httpException = (HttpStatusCodeException) ex;
DataErrorEnum error = DataErrorEnum.getErrorEnumByException(httpException);
String errorMessage = httpException.getResponseBodyAsString();
dataResponse = new DataResponse(errorMessage, error, DataStatusEnum.ERROR);
return dataResponse;
} catch (HttpServerErrorException ex) {
HttpStatusCodeException httpException = (HttpStatusCodeException) ex;
DataErrorEnum error = DataErrorEnum.getErrorEnumByException(httpException);
String errorMessage = httpException.getResponseBodyAsString();
dataResponse = new DataResponse(errorMessage, error, DataStatusEnum.ERROR);
return dataResponse;
} catch (RestClientException ex) {
// if it comes here, then it means some of the servers are down so adding it into block list
ShardMappings.blockHost(hostname);
}
}
if (ClientUtils.isEmpty(hostnames)) {
dataResponse = new DataResponse(null, DataErrorEnum.PERT_ERROR, DataStatusEnum.ERROR);
} else if (response == null) { // either all the servers are down or all the servers were in block list
dataResponse = new DataResponse(null, DataErrorEnum.SERVICE_UNAVAILABLE, DataStatusEnum.ERROR);
}
return dataResponse;
}
}
danh sách chặn tôi giữ-on nhận được cập nhật từ một sợi nền mỗi 1 phút. Nếu bất kỳ máy chủ là xuống và không đáp ứng, sau đó tôi cần phải chặn máy chủ bằng cách sử dụng này -
ShardMappings.blockHost(hostname);
Và để kiểm tra xem bất kỳ máy chủ là trong danh sách chặn hay không, tôi sử dụng này -
ShardMappings.isBlockHost(hostname);
Tôi đang trả lại SERVICE_UNAVAILABLE
nếu máy chủ không hoạt động hoặc trong danh sách chặn, trên cơ sở response == null
kiểm tra, không chắc chắn đó có phải là phương pháp phù hợp hay không.
Tôi không tuân thủ Nguyên tắc về trách nhiệm duy nhất ở đây Tôi đoán là tất cả. Bất cứ ai cũng có thể cung cấp một ví dụ cách tốt nhất để sử dụng nguyên tắc SRP ở đây là gì.
Sau khi suy nghĩ rất nhiều, tôi đã có thể trích xuất các host lớp như đưa ra dưới đây nhưng không chắc chắn cách tốt nhất để sử dụng trong lớp học trênDataExecutorTask
của tôi là gì.
public class Hosts {
private final LinkedList<String> hostsnames = new LinkedList<String>();
public Hosts(final List<String> hosts) {
checkNotNull(hosts, "hosts cannot be null");
this.hostsnames.addAll(hosts);
}
public Optional<String> getNextAvailableHostname() {
while (!hostsnames.isEmpty()) {
String firstHostname = hostsnames.removeFirst();
if (!ClientUtils.isEmpty(firstHostname) && !ShardMappings.isBlockHost(firstHostname)) {
return Optional.of(firstHostname);
}
}
return Optional.absent();
}
public boolean isEmpty() {
return hostsnames.isEmpty();
}
}
Offtopic: Ưu điểm của việc sử dụng mẫu trong Spring là gì? –
@PantaRhei RestTemplate là một trình bao bọc tiện lợi hơn HttpClient. Nó đơn giản hóa và tóm tắt một số trường hợp và mã sử dụng phổ biến nhất. – john