遗留非springboot传统项目接入eureka注册与服务发现

来源:互联网 发布:ps美工教程视频 编辑:程序博客网 时间:2024/06/05 16:24

推荐: jeesuite开发框架,免费开源、一站式解决方案。

最近规划自动化运维以及统一监控需求,鉴于目前公司内部大部分项目采用spring cloud体系架构、另外还有一些老的传统spring web的项目,于是就考虑把老的项目通过低成本改造的方式接入spring cloud体系,也就是可以通过eureka注册和服务发现、通过zuul服务路由。

说干就干,通过eureka官方实例和研究spring boot注册eureka源码发现这个也很容易实现,所以废话不多说,直接贴代码了 。

首先加入项目依赖(maven为例)
<dependency>    <groupId>com.netflix.eureka</groupId>    <artifactId>eureka-client</artifactId>    <version>1.4.12</version>    <exclusions>        <exclusion>          <groupId>javax.servlet</groupId>          <artifactId>servlet-api</artifactId>        </exclusion>        <exclusion>          <groupId>com.google.guava</groupId>          <artifactId>guava</artifactId>        </exclusion>        <exclusion>          <groupId>com.fasterxml.jackson.core</groupId>          <artifactId>jackson-annotations</artifactId>        </exclusion>        <exclusion>          <groupId>javax.ws.rs</groupId>          <artifactId>jsr311-api</artifactId>        </exclusion>    </exclusions></dependency>    <dependency>      <groupId>com.netflix.archaius</groupId>      <artifactId>archaius-core</artifactId>      <version>0.7.4</version>      <exclusions>        <exclusion>          <groupId>com.fasterxml.jackson.core</groupId>          <artifactId>jackson-annotations</artifactId>        </exclusion>      </exclusions>    </dependency>    <dependency>      <groupId>org.springframework.cloud</groupId>      <artifactId>spring-cloud-netflix-core</artifactId>      <version>1.2.6.RELEASE</version>      <exclusions>        <exclusion>          <groupId>org.springframework.boot</groupId>          <artifactId>spring-boot-autoconfigure</artifactId>        </exclusion>      </exclusions>    </dependency>
加入配置文件
eureka.region=defaulteureka.registration.enabled=trueeureka.preferSameZone=trueeureka.shouldUseDns=falseeureka.serviceUrl.default=http://192.168.1.100:7861/eurekaeureka.decoderName=JacksonJsoneureka.name=demoeureka.vipAddress=${eureka.name}-serviceeureka.port=8081eureka.homePageUrl=http://192.168.1.101:${eureka.port}eureka.healthCheckUrl=http://192.168.1.101:${eureka.port}/service/healtheureka.statusPageUrl=http://192.168.1.101:${eureka.port}/service/info
  • spring.cloud.client.ipAddress :为自定义变量
  • healthCheckUrl,statusPageUrl接口可以不要,但是为了监控可以自己实现一个简单的接口即可
初始化eureka客户端
private void initEurekaClient() throws Exception{        Properties properties = new Properties();        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("eureka.properties");        properties.load(inputStream);        //        properties.setProperty("eureka.ipAddr", IpUtils.getLocalIpAddr());        instanceId = properties.getProperty("eureka.ipAddr") + ":" + properties.getProperty("eureka.ipAddr") + "/" + properties.getProperty("eureka.name");        properties.setProperty("eureka.instanceId", instanceId);        ConfigurationManager.loadProperties(properties);        MyDataCenterInstanceConfig instanceConfig = new MyDataCenterInstanceConfig();        InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get();        applicationInfoManager = new ApplicationInfoManager(instanceConfig, instanceInfo);        DefaultEurekaClientConfig clientConfig = new DefaultEurekaClientConfig();        eurekaClient = new DiscoveryClient(applicationInfoManager, clientConfig);}
注册服务
private void waitForRegistrationWithEureka() {        applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.STARTING);        try {            Thread.sleep(2000);        } catch (InterruptedException e) {        }        applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.UP);        long startTime = System.currentTimeMillis();        //开启一个线程验证注册结果        new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    if (System.currentTimeMillis() - startTime > VERIFY_WAIT_MILLIS) {                        log.warn(" >>>> service registration status not verify,please check it!!!!");                        return;                    }                    try {                        List<InstanceInfo> serverInfos = eurekaClient.getInstancesByVipAddress(vipAddress, false);                        for (InstanceInfo nextServerInfo : serverInfos) {                            if (nextServerInfo.getIPAddr().equals(IpUtils.LOCAL_BACK_IP)                                    || nextServerInfo.getIPAddr().equals(IpUtils.getLocalIpAddr())) {                                String instanceInfoJson = JsonUtils.getMapper().writerWithDefaultPrettyPrinter()                                        .writeValueAsString(nextServerInfo);                                log.info("verifying service registration with eureka finished,instance:\n{}",                                        instanceInfoJson);                                return;                            }                        }                    } catch (Throwable e) {                    }                    try {                        Thread.sleep(5000);                    } catch (Exception e1) {                    }                    log.info("Waiting 5s... verifying service registration with eureka ...");                }            }        }).start();    }

通过这几步就完成了eureka的注册,登录eureka控制台你将能看到对应注册信息。但是在zuul转发调用过程发现一个问题:无法识别hostname,如果你们的服务器之间没有做hostname同步就需要继续改造,于是就看了下springboot注册eureka有一个配置项eureka.instance.preferIpAddress,所以我们也可以模仿他的实现。于是在初始化客户端的时候我们需要这样改造:

MyDataCenterInstanceConfig instanceConfig = new MyDataCenterInstanceConfig(){            @Override            public String getHostName(boolean refresh) {                String hostName = super.getHostName(refresh);                if(ResourceUtils.getBoolean("eureka.preferIpAddress")){                    hostName = IpUtils.getLocalIpAddr();                }                return hostName;            }            @Override            public String getIpAddress() {                return IpUtils.getLocalIpAddr();            }};

这样,注册的真实服务地址就是ip了。服务注册就搞定收工了。

接下来就是服务发现,及与其他springboot项目一样通过注册中心vipAddress互相调用。实际过程就是调用前去eureka拿一个真实地址替换vipAddress变量。

获取真实服务地址

public String getRealServerHost(String serviceId){    InstanceInfo serverInfo = eurekaClient.getNextServerFromEureka(serviceId, false);    String realServerName = serverInfo.getIPAddr() + ":" + serverInfo.getPort();    return realServerName;}

下面是我实现的几个resttemplate

public class EurekaRestTemplateBuilder {    private static Map<String, RestTemplate> restTemplates = new HashMap<>();    public static synchronized RestTemplate build(ClientHttpRequestInterceptor ...interceptors ){        return build("default", interceptors);    }    public static synchronized RestTemplate build(String name,ClientHttpRequestInterceptor ...interceptors ){        if(restTemplates.containsKey(name))return restTemplates.get(name);        SimpleClientHttpRequestFactory factory = new EurekaClientHttpRequestFactory();          factory.setReadTimeout(15000);//ms          factory.setConnectTimeout(5000);//ms         RestTemplate restTemplate = new RestTemplate(factory);        List<ClientHttpRequestInterceptor> interceptorList = new ArrayList<>();        interceptorList.add(new RestTemplateAutoHeaderInterceptor());        if(interceptors != null && interceptors.length > 0){            for (ClientHttpRequestInterceptor interceptor : interceptors) {                interceptorList.add(interceptor);            }        }        restTemplate.setInterceptors(interceptorList);        //        restTemplate.setErrorHandler(new CustomResponseErrorHandler());        //        restTemplates.put(name, restTemplate);        return restTemplate;    }    private static class EurekaClientHttpRequestFactory extends SimpleClientHttpRequestFactory{        @Override        public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {            uri = convertToRealUri(uri);            return super.createRequest(uri, httpMethod);        }        @Override        public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {            uri = convertToRealUri(uri);            return super.createAsyncRequest(uri, httpMethod);        }        private URI convertToRealUri(URI uri){            String serviceId = uri.getHost();            try {                               String realHost = EurekaRegistry.getInstance().getRealServerHost(serviceId);                uri = new URI(uri.toString().replace(serviceId, realHost));                return uri;            } catch (Exception e) {                throw new RuntimeException(e);            }        }    }}

接下来就可以调用其他eureka注册服务了。

private RestTemplate restTemplate = EurekaRestTemplateBuilder.build();  public List<IdNamePair> getProvinces() {    ParameterizedTypeReference<List<IdNamePair>> arearesponseType = new ParameterizedTypeReference<List<IdNamePair>>() {    };    List<IdNamePair> lists = restTemplate        .exchange("http://DEMO-SERVICE/region/provinces", HttpMethod.GET, null, arearesponseType)        .getBody();    return lists;  }
ZUUL转发配置
zuul.routes.demo.path=/demo/**zuul.routes.demo.serviceId=demo-service

到此,服务注册和服务发现都完成了。

有任何问题,请加技术群:230192763讨论

原创粉丝点击