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

推荐: 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=default
eureka.registration.enabled=true
eureka.preferSameZone=true
eureka.shouldUseDns=false
eureka.serviceUrl.default=http://192.168.1.100:7861/eureka
eureka.decoderName=JacksonJson

eureka.name=demo
eureka.vipAddress=${eureka.name}-service
eureka.port=8081
eureka.homePageUrl=http://192.168.1.101:${eureka.port}
eureka.healthCheckUrl=http://192.168.1.101:${eureka.port}/service/health
eureka.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讨论

转载于:https://my.oschina.net/vakinge/blog/1590261

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值