Wie befolge ich das Prinzip der Einzelverantwortung in meinem HttpClient-Executor?

Ich benutzeRestTemplate wie meinHttpClient, um die URL auszuführen, und der Server gibt eine JSON-Zeichenfolge als Antwort zurück. Der Kunde ruft diese Bibliothek an, indem er @ übergibDataKey Objekt, das @ huserId drin

Mit dem gegebenenuserId, Ich werde herausfinden, auf welchen Computern ich die Daten abrufen und diese dann in einem @ speichern kanLinkedList, damit ich sie nacheinander ausführen kann.Nachdem werde ich prüfen, ob der erste Hostname in der Sperrliste steht oder nicht. Wenn es nicht in der Sperrliste enthalten ist, erstelle ich eine URL mit dem ersten Hostnamen in der Liste und führe sie aus. Wenn die Antwort erfolgreich ist, sende ich die Antwort zurück. Aber sagen wir mal, wenn dieser erste Hostname in der Sperrliste ist, dann werde ich versuchen, den zweiten Hostnamen in der Liste zu bekommen und die URL zu erstellen und auszuführen, also im Grunde genommen,suchen Sie zuerst den Hostnamen, der nicht in der Sperrliste enthalten ist, bevor Sie die URL eingeben.Now, lassen Sie uns sagen, wenn wir den ersten Hostnamen ausgewählt haben, der nicht in der Sperrliste enthalten war, und die URL ausgeführt haben und der Server ausfiel oder nicht reagierte, dann werde ich den zweiten Hostnamen in der Liste ausführen und dies so lange tun, bis Sie eine erfolgreiche Antwort erhalten .Aber stellen Sie sicher, dass sie nicht auch in der Sperrliste enthalten sind, also müssen wir den obigen Punkt befolgen.Wenn alle Server inaktiv sind oder sich in der Sperrliste befinden, kann ich den Fehler, dass der Dienst nicht verfügbar ist, einfach protokollieren und zurückgeben.

Below ist meine DataClient-Klasse, die vom Kunden aufgerufen wird und dieDataKey Objekt zugetData Methode

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;
    }
}

Below ist meine DataExecutorTask-Klasse:

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;
    }
}

Meine Sperrliste wird weiterhin alle 1 Minute von einem anderen Hintergrund-Thread aktualisiert. Wenn ein Server ausfällt und nicht antwortet, muss ich diesen Server mit diesem Befehl blockieren -

ShardMappings.blockHost(hostname);

Und um zu überprüfen, ob sich ein Server in der Sperrliste befindet oder nicht, verwende ich Folgendes: -

ShardMappings.isBlockHost(hostname);

Ich komme zurückSERVICE_UNAVAILABLE Wenn Server inaktiv oder in der Sperrliste sind, basierend aufresponse == null prüfen, nicht sicher, ob es ein richtiger Ansatz ist oder nicht.

Ich folge hier nicht dem Prinzip der Einzelverantwortung.. Kann mir jemand ein Beispiel geben, wie man das SRP-Prinzip am besten einsetzt.

Nachdem ich viel nachgedacht hatte, konnte ich die Hosts-Klasse wie unten angegeben extrahieren, aber nicht sicher,was ist der beste Weg, um dies in meinem oben @ verwend DataExecutorTask Klasse

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();
    }
}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage