Измените возвращаемый экземпляр клиента, используя файл свойств (поведение перезаписи стартера и автоматической ленты eureka) - PullRequest
0 голосов
/ 06 сентября 2018

Введение

Итак, у нас есть стартер, который мы используем как родительский, и у него есть различные шаблоны и автоконфигурации, которые также загружают симулированных клиентов.

Симулированные клиенты используют eureka discoveryвнизу, чтобы перебрать сервисы.

Вот пример одного из наших симулированных клиентов:

import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(name="decide-proxy")
public interface DecideControllerApiClient extends DecideControllerApi {
}

В проектах, которые используютэтой весенней загрузкой (а также облачным стартером) в качестве родителя (в нашем pom.xml) я хотел бы иметь возможность перейти к файлу свойств и сделать что-то вроде этого:

eureka.client.filter.enabled=true
eureka.client.filter.services.doc-tools.host=localhost
eureka.client.filter.services.doc-tools.port=8015

У меня естьспособ сделать это сейчас, но он предполагает использование Аспектов и рефлексии, и это, кажется, замедляет мои проекты - это большой уродливый взлом.

Так есть ли способ сделать это через свойство ленты иличто-то еще?

Желательно без изменения стартового кода?

Вопрос в том, как мы можем изменить симулированный возвращенный клиентом экземпляр, используя файл свойств.По сути, как мы можем переопределить поведение ленты стартера и eureka.

Current Hack

Итак, я увидел следующую ссылку: https://stackoverflow.com/a/42413801/1688441

И на основании этого я создалКажется, работает следующее:

   import com.netflix.appinfo.InstanceInfo;
    import eureka.InstanceBuildVersionProperties.InstanceHostFilter;
    import lombok.RequiredArgsConstructor;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient.EurekaServiceInstance;
    import org.springframework.stereotype.Component;

    import java.lang.reflect.Field;
    import java.net.URI;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    @RequiredArgsConstructor
    @Aspect
    public class EurekaInstanceHostFilter {
        private final Logger logger = LoggerFactory.getLogger(this.getClass());

        private final String versionMetadataKey;
        private final InstanceBuildVersionProperties filters;

        @SuppressWarnings("unchecked")
        @Around("execution(public * org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient.getInstances(..))")
        public Object filterInstances(ProceedingJoinPoint jp) throws Throwable {
            if (filters == null || !filters.isEnabled()) logger.error("Should not be filtering...");
            List<ServiceInstance> instances = (List<ServiceInstance>) jp.proceed();

            String serviceId = (String) jp.getArgs()[0];
            InstanceHostFilter filter = filters.getServices().get(serviceId);

            if(filter != null){
                instances.forEach( instance -> {


                    try {

                        Class<?> clazz = EurekaServiceInstance.class;
                        Class<?> clazzInfo = InstanceInfo.class;

                        Field instanceField = clazz.getDeclaredField("instance");
                        instanceField.setAccessible(true);
                        InstanceInfo instanceInfo = (InstanceInfo) instanceField.get(instance);

                        String originalHostName =instanceInfo.getHostName();
                        int originalPort =instanceInfo.getPort();

                        //SET THE VALUES

                        String changeInstanceId = filter.getHost() + ":" + instance.getServiceId() + ":" +filter.getPort();
                        setField(instanceInfo, clazzInfo, "instanceId", changeInstanceId );

                        //HomePageURL
                        String newHomePageUrl = instanceInfo.getHomePageUrl().replace(originalHostName, filter.getHost())   .replace(originalPort+"", filter.getPort()+"");
                        setField(instanceInfo, clazzInfo, "homePageUrl", newHomePageUrl );

                        //StatusPageUrl
                        String statusPageUrl = instanceInfo.getStatusPageUrl().replace(originalHostName, filter.getHost())  .replace(originalPort+"", filter.getPort()+"");
                        setField(instanceInfo, clazzInfo, "statusPageUrl", statusPageUrl );

                        //healthCheckURL
                        String healthCheckUrl = instanceInfo.getHealthCheckUrl().replace(originalHostName, filter.getHost())    .replace(originalPort+"", filter.getPort()+"");
                        setField(instanceInfo, clazzInfo, "healthCheckUrl", healthCheckUrl );

                        //hostName
                        String hostName = instanceInfo.getHostName().replace(originalHostName, filter.getHost());
                        setField(instanceInfo, clazzInfo, "hostName", hostName );

                        setIntField(instanceInfo, clazzInfo, "port", filter.getPort());

                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }


                });

            }

            return instances;
        }

        private void setField(Object instanceInfo, Class<?> clazzInfo, String fieldName, String value) throws NoSuchFieldException, IllegalAccessException {
            Field instanceId = clazzInfo.getDeclaredField(fieldName);
            instanceId.setAccessible(true);
            instanceId.set(instanceInfo, value);
        }

        private void setIntField(Object instanceInfo, Class<?> clazzInfo, String fieldName, int value) throws NoSuchFieldException, IllegalAccessException {
            Field instanceId = clazzInfo.getDeclaredField(fieldName);
            instanceId.setAccessible(true);
            instanceId.setInt(instanceInfo, value);
        }

    }

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    @Configuration
    @ConditionalOnProperty(name = "eureka.client.filter.enabled", havingValue = "true")
    @EnableConfigurationProperties(InstanceBuildVersionProperties.class)
    public class EurekaInstanceHostFilterAutoConfig {

        @Value("${eureka.instance.metadata.keys.version:instanceBuildVersion}")
        private String versionMetadataKey;

        @Bean
        @ConditionalOnProperty(name = "eureka.client.filter.enabled", havingValue = "true")
        public EurekaInstanceHostFilter eurekaInstanceBuildVersionFilter(InstanceBuildVersionProperties filters) {
            return new EurekaInstanceHostFilter(versionMetadataKey, filters);
        }
    }


import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.HashMap;
import java.util.Map;

import static org.apache.commons.lang3.ArrayUtils.contains;

@ConfigurationProperties("eureka.client.filter")
public class InstanceBuildVersionProperties {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * Indicates whether or not service instances versions should be filtered
     */
    @Getter @Setter
    private boolean enabled = false;

    /**
     * Map of service instance version filters.
     * The key is the service name and the value configures a filter set for services instances
     */
    @Getter
    private Map<String, InstanceHostFilter> services = new HashMap<>();

    public boolean isKept(String serviceId) {
        logger.debug("Considering service {} instance", serviceId);
        if (services.containsKey(serviceId)) {
            InstanceHostFilter filter = services.get(serviceId);
            //TODO:
            return true;
        }
        return true;
    }

    @Getter @Setter
    public static class InstanceHostFilter {
        /**
         * host to use
         */
        private String host;
        private int port;
    }
}

Приведенный выше код, который я заметил, заставил мой проект немного замедлиться.Кроме того, он очень хакерский из-за использования отражения и аспектов.

Другие идеи

Единственная другая идея - возможно начать играть с условной загрузкой конфигураций в самом стартере.Таким образом, я мог бы попытаться загрузить либо одного симулированного клиента, либо другого симулированного клиента в зависимости от свойств в файле свойств приложения.

Конечно, это, вероятно, означало бы, что мы должны были бы включить поддержку отладки в каждый шаблон, симулировать клиента и автоматическую настройку для каждого микросервиса.

Идеи?

Обновление

Мы пытались использовать файл свойств, а также одно из свойств ленты плюс имя, но это не сработало.Что-то вроде:

decide-proxy.ribbon.listOfServers=

1 Ответ

0 голосов
/ 07 сентября 2018

У меня работает следующая конфигурация в bootstrap.yml,

ribbon:
  eureka:
    enabled: false

my-service:
  ribbon:
    listOfServers: 192.168.1.217:9010

Я настраиваю его в моем прокси-сервере zuul, чтобы он мог ссылаться на сервисы, которые не зарегистрированы в той же eureka. Таким образом, он отключит все поиски eureka.

--- обновлено ---

Обратитесь к следующей ссылке, она может указать какой-либо сервис для использования указанного списка серверов без отключения всех поисков eureka. Как отключить поиск eureka для конкретного @ FeignClient , указать

 my-service:
    ribbon:     
      NIWSServerListClassName:com.netflix.loadbalancer.ConfigurationBasedServerList
      listOfServers: server1:18201,server2:18201

к вашим услугам

...