由于公司一些老的项目要对接新项目,而新项目是springCloud框架,需要在老项目里面集成下Eureka,(当然,如果新项目提供IP的调用方式,就可以用传统的HTTP调用方式来调用)
注意:此次只是集成Eureka,并不涉及到Feign
项目依赖
<dependency> <groupId>com.netflix.eureka</groupId> <artifactId>eureka-client</artifactId> <version>1.7.0</version> </dependency> <!-- Ribbon 负载均衡 --> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon-eureka</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon</artifactId> <version>2.2.5</version> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon-core</artifactId> <version>2.2.5</version> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon-httpclient</artifactId> <version>2.2.5</version> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon-loadbalancer</artifactId> <version>2.2.5</version> </dependency> <dependency> <groupId>com.netflix.archaius</groupId> <artifactId>archaius-core</artifactId> <version>0.7.4</version> </dependency>
配置文件
ribbon.properties
注意:ribbon由于配置是customer-svc服务名,所以只能获取到customer-svc服务对应的ip地址,如果还要获取其他服务,就需要把下面的ribbon的三行配置copy一下,把customer-svc改成你需要调用的其他服务名即可
# customer-svc:微服务Eureka上对应的服务名 customer-svc.ribbon.DeploymentContextBasedVipAddresses=customer-svc # 固定写法,customer-svc使用的ribbon负载均衡器 customer-svc.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList # 每分钟更新customer-svc对应服务的可用地址列表 customer-svc.ribbon.ServerListRefreshInterval=60000
# 控制是否注册自身到eureka中 eureka.registration.enabled=false # eureka相关配置 eureka.preferSameZone=true eureka.shouldUseDns=false eureka.serviceUrl.default=http://10.0.0.0:8671/eureka eureka.decoderName=JacksonJson
初始化Ribbon
package com.movitech.mbox.modules.feign; import com.netflix.appinfo.MyDataCenterInstanceConfig; import com.netflix.config.ConfigurationManager; import com.netflix.discovery.DefaultEurekaClientConfig; import com.netflix.discovery.DiscoveryManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import java.io.IOException; public class EurekaInitAndRegisterListener implements ServletContextListener { /** * 默认的ribbon配置文件名, 该文件需要放在classpath目录下 */ public static final String RIBBON_CONFIG_FILE_NAME = "ribbon.properties"; private static Logger log = LoggerFactory.getLogger(EurekaInitAndRegisterListener.class); @Override public void contextInitialized(ServletContextEvent sce) { log.info("开始初始化ribbon"); try { // 加载ribbon配置文件 ConfigurationManager.loadPropertiesFromResources(RIBBON_CONFIG_FILE_NAME); } catch (IOException e) { e.printStackTrace(); log.error("ribbon初始化失败"); throw new IllegalStateException("ribbon初始化失败"); } // 初始化Eureka Client DiscoveryManager.getInstance().initComponent(new MyDataCenterInstanceConfig(), new DefaultEurekaClientConfig()); log.info("ribbon初始化完成"); } @Override public void contextDestroyed(ServletContextEvent sce) { DiscoveryManager.getInstance().shutdownComponent(); } }
web.xml
<listener> <listener-class>xx.xx.modules.feign.EurekaInitAndRegisterListener</listener-class> </listener>
获取服务地址
package com.movitech.mbox.modules.feign; import com.movitech.mbox.modules.feign.vo.AlanServiceAddress; import com.netflix.client.ClientFactory; import com.netflix.loadbalancer.DynamicServerListLoadBalancer; import com.netflix.loadbalancer.RoundRobinRule; import com.netflix.loadbalancer.Server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class AlanServiceAddressSelector { private static Logger log = LoggerFactory.getLogger(AlanServiceAddressSelector.class); private static RoundRobinRule chooseRule = new RoundRobinRule(); /** * 根据轮询策略选择一个地址 * * @param clientName * ribbon.properties配置文件中配置项的前缀名, 如myclient * @return null表示该服务当前没有可用地址 */ public static AlanServiceAddress selectOne(String clientName) { // ClientFactory.getNamedLoadBalancer会缓存结果, 所以不用担心它每次都会向eureka发起查询 DynamicServerListLoadBalancer lb = (DynamicServerListLoadBalancer) ClientFactory .getNamedLoadBalancer(clientName); Server selected = chooseRule.choose(lb, null); if (null == selected) { log.warn("服务{}没有可用地址", clientName); return null; } log.debug("服务{}选择结果:{}", clientName, selected); return new AlanServiceAddress(selected.getPort(), selected.getHost()); } /** * 选出该服务所有可用地址 * * @param clientName * @return */ public static List<AlanServiceAddress> selectAvailableServers(String clientName) { DynamicServerListLoadBalancer lb = (DynamicServerListLoadBalancer) ClientFactory .getNamedLoadBalancer(clientName); List<Server> serverList = lb.getReachableServers(); if (serverList.isEmpty()) { log.warn("服务{}没有可用地址", clientName); return Collections.emptyList(); } log.debug("服务{}所有选择结果:{}", clientName, serverList); return serverList.stream().map(server -> new AlanServiceAddress(server.getPort(), server.getHost())) .collect(Collectors.toList()); } }
地址实体类:
package com.movitech.mbox.modules.feign.vo; public class AlanServiceAddress { private int port; private String host; public AlanServiceAddress() { } public AlanServiceAddress(int port, String host) { this.port = port; this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } /** * 将服务地址转换为 http://主机名:端口/ 的格式 * @return */ @Override public String toString() { StringBuilder sb = new StringBuilder(15 + host.length()); sb.append("http://").append(host).append(":").append(port).append("/"); return sb.toString(); } }
使用方法
JSONObject param = (JSONObject) JSON.toJSON(feignVO); AlanServiceAddress addr = AlanServiceAddressSelector.selectOne("customer-svc"); String response = HttpUtil.httpPost(addr+"v1/createRecommend",param,null);
借鉴https://www.cnblogs.com/xandersu/p/8504740.html
踩坑
项目集成后,测试环境tomcat一直启动报错
错误信息报的是这个:Failed to initalize discoveryClient! 这个一看就可能是HTTPCLient的问题,看了下初始化EurekaClient的底层代码,把pom文件里面的HTTPCLient版本升级成
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.4.1</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.1</version> </dependency>
然后重新启动就可以了,至于为什么低版本的不行,还不是很清楚