<!-- 服务注册-客户端 --> <dependency> <groupId>com.netflix.eureka</groupId> <artifactId>eureka-client</artifactId> <version>1.4.11</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> <!--客户端注册到eureka就是用的此工具包--> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-client</artifactId> <version>2.22.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-json-provider</artifactId> <version>2.9.4</version> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jackson</artifactId> <version>2.25.1</version> </dependency>
import com.netflix.appinfo.DataCenterInfo; import com.netflix.appinfo.InstanceInfo; import com.netflix.appinfo.LeaseInfo; import com.netflix.appinfo.MyDataCenterInfo; import com.thoughtworks.xstream.annotations.XStreamAlias; import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; import javax.ws.rs.client.*; import javax.ws.rs.core.Response; import java.util.HashMap; import java.util.Map; import static com.netflix.appinfo.DataCenterInfo.Name.MyOwn; /** * eureka注册中心工具类 * @author GaoYuan * @date 2019/1/6 下午3:46 */ public class EurekaUtils { private static String ipAddr = "192.168.0.231"; private static String instanceId = ipAddr + ":demo:8087"; private static String appName = "demo"; private static String appGroupName; private static String sid = "na"; private static com.netflix.appinfo.InstanceInfo.PortWrapper port = new com.netflix.appinfo.InstanceInfo.PortWrapper(true, 8087); private static com.netflix.appinfo.InstanceInfo.PortWrapper securePort = new com.netflix.appinfo.InstanceInfo.PortWrapper(false, 443); private static String homePageUrl = "http://"+ipAddr+":"+port.getPort()+"/demo"; private static String statusPageUrl = "http://"+ipAddr+":"+port.getPort()+"/demo/info"; private static String healthCheckUrl = "http://"+ipAddr+":"+port.getPort()+"/demo/health"; private static String secureHealthCheckUrl = null; private static String vipAddress = "demo"; private static String secureVipAddress = "demo"; private static String statusPageRelativeUrl = "/demo/info"; private static String statusPageExplicitUrl = null; private static String healthCheckRelativeUrl = "/demo/health"; private static String healthCheckSecureExplicitUrl = null; private static String vipAddressUnresolved = "demo"; private static String secureVipAddressUnresolved = "demo"; private static String healthCheckExplicitUrl = null; private static int countryId = 1; private static boolean isSecurePortEnabled = false; private static boolean isUnsecurePortEnabled = true; private static DataCenterInfo dataCenterInfo = new MyDataCenterInfo(MyOwn); private static String hostName = ipAddr; private static InstanceInfo.InstanceStatus status = InstanceInfo.InstanceStatus.UP; private static InstanceInfo.InstanceStatus overriddenstatus = InstanceInfo.InstanceStatus.UP; private static boolean isInstanceInfoDirty = true; /** 续租信息 * renewalIntervalInSecs 租期更新时间间隔 * durationInSecs 租期到期时间,到期就下线 */ private static LeaseInfo leaseInfo = new LeaseInfo(2, 30, 0L, 0L, 0, 0, 0); private static boolean isCoordinatingDiscoveryServer = false; // private static Map<String, String> metadata = new ConcurrentHashMap<>(); @XStreamAlias("metadata") private static volatile Map<String, String> metadata = new HashMap<String, String>(); private static long lastUpdatedTimestamp = System.currentTimeMillis(); private static long lastDirtyTimestamp = System.currentTimeMillis(); private static volatile InstanceInfo.ActionType actionType = null; private static String asgName = null; private static String version = "unknown"; public static void main(String[] args){ String url = "http://eureka-node1:11001/eureka/"; com.netflix.appinfo.InstanceInfo instanceInfo = new com.netflix.appinfo.InstanceInfo( instanceId, appName, appGroupName, ipAddr, sid, port, securePort, homePageUrl, statusPageUrl, healthCheckUrl, secureHealthCheckUrl, vipAddress, secureVipAddress, countryId, dataCenterInfo, hostName, status, overriddenstatus, leaseInfo, isCoordinatingDiscoveryServer, (HashMap)metadata, lastUpdatedTimestamp, lastDirtyTimestamp, actionType, asgName); InstanceInfo.Builder builder = new InstanceInfo.Builder(instanceInfo); builder.setStatusPageUrl(statusPageRelativeUrl, statusPageExplicitUrl); builder.setHealthCheckUrls(healthCheckRelativeUrl, healthCheckExplicitUrl, healthCheckSecureExplicitUrl); builder.setVIPAddress(vipAddress); builder.setSecureVIPAddress(secureVipAddress); Client jerseyClient = ClientBuilder.newClient(); // 基本认证的Feature HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("admin", "123456"); // 将Feature注册到Jersey Client中 WebTarget target = jerseyClient .register(feature) .target(url) .path("/apps/"+ instanceInfo.getAppName()); //获取执行器 Invocation.Builder invocationBuilder = target.request(javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE); //添加头信息 invocationBuilder.header("Accept-Encoding", "gzip"); invocationBuilder.header("Content-Type", "application/json"); //对当前URI执行GET方法请求;得到响应对象 Map<String,Object> map = new HashMap<>(); map.put("instance", builder.getRawInstance()); Response response = invocationBuilder.post(Entity.entity(map, javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE)); //从响应对象中获取须要的内容 - 返回状态204表示成功(你没看错,就是204) System.out.println(response.getStatus()); System.out.println(response); } }
/** * 对外提供监控接口 * @author GaoYuan * @date 2019/1/10 上午8:39 */ @RestController public class EurekaController { @GetMapping("/health") public Object health(){ Map<String, String> map = new HashMap<>(2); map.put("description", "Spring Cloud Eureka Discovery Client"); map.put("status", "UP"); return map; } @GetMapping("/info") public Object info(){ Map<String, String> map = new HashMap<>(2); map.put("name", "管理平台"); return map; } }
能够发现,额外引入了 jersey ,由于eureka的客户端就是经过jersey进行http请求的(后面会解释这里是怎么知道的)。java
首先,咱们须要解决的问题以下:node
下面咱们挨个解决问题git
官方文档 RestApi(https://github.com/Netflix/eureka/wiki/Eureka-REST-operations)github
经过阅读官方文档,能够看到注册接口:spring
Operation | HTTP action | Descrition |
---|---|---|
注册 | POST /eureka/v2/apps/appID | 输入:JSON/XML,返回:204表示成功 |
注:这里确实是返回204表示成功。json
官方列举了注册的参数,可是,只给出了xml格式的案例,对于咱们经常使用的方式并不友好。接下来咱们在尝试经过eureka-client来获取【参数对象】。api
经过 eureka-client 的debug日志,能够发现,注册的方法在 com.netflix.discovery.DiscoveryClient
中。咱们继续搜索 register 方法,在 825 行能够看到以下代码:springboot
boolean register() throws Throwable { logger.info(PREFIX + "{}: registering service...", appPathIdentifier); EurekaHttpResponse<Void> httpResponse; try { httpResponse = eurekaTransport.registrationClient.register(instanceInfo); } catch (Exception e) { logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e); throw e; } if (logger.isInfoEnabled()) { logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode()); } return httpResponse.getStatusCode() == 204; }
主要代码是微信
httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
其中 instanceInfo
就是咱们所须要的【参数对象】,完整路径是 com.netflix.appinfo.InstanceInfo
,咱们此处打上断点,能够看到 instanceInfo 中的参数内容,以下:app
参数对象 咱们已经获取到了,经过调用 InstanceInfo 提供的构造函数便可。
接下来咱们查看具体的注册方法
DiscoveryClient 中的 eurekaTransport.registrationClient.register()
方法, 这里的 registrationClient 是 interface EurekaHttpClient
接口。
咱们经过快捷键能够知道实现 EurekaHttpClient 的实现类有 AbstractJerseyEurekaHttpClient
和 EurekaHttpClientDecorator
在两个实现类的 regist 中都打上断点,能够发现最终调用了 AbstractJerseyEurekaHttpClient
的 注册方法,具体实现方法以下:
@Override public EurekaHttpResponse<Void> register(InstanceInfo info) { String urlPath = "apps/" + info.getAppName(); ClientResponse response = null; try { Builder resourceBuilder = jerseyClient.resource(serviceUrl).path(urlPath).getRequestBuilder(); addExtraHeaders(resourceBuilder); response = resourceBuilder .header("Accept-Encoding", "gzip") .type(MediaType.APPLICATION_JSON_TYPE) .accept(MediaType.APPLICATION_JSON) .post(ClientResponse.class, info); return anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build(); } finally { if (logger.isDebugEnabled()) { logger.debug("Jersey HTTP POST {}/{} with instance {}; statusCode={}", serviceUrl, urlPath, info.getId(), response == null ? "N/A" : response.getStatus()); } if (response != null) { response.close(); } } }
由此可发现,此方法使用 jerseyClient
进行接口请求,相关核心代码都出现了。
接下来,咱们在传统的SSM项目中,构造 jersey 调用便可。下面就不啰嗦了
// 基本认证的Feature HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("admin", "123456"); // 将Feature注册到Jersey Client中 WebTarget target = jerseyClient .register(feature) .target(url) .path("/apps/"+ instanceInfo.getAppName());
其实就是对外提供/health接口就好了,注意,此接口不要有权限拦截。
@GetMapping("/health") public Object health(){ Map<String, String> map = new HashMap<>(2); map.put("description", "Spring Cloud Eureka Discovery Client"); map.put("status", "UP"); return map; }
执行 EurekaUtils.main() 方法
204 InboundJaxrsResponse{context=ClientResponse{method=POST, uri=http://eureka-node1:11001/eureka/apps/MDM-MC, status=204, reason=No Content}}
注册成功。
须要security.basic访问
HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("admin", "123456");
注册地址不对,这里的url使用单一地址,且不要加上 帐号:密码@
String url = "http://eureka-node1:11001/eureka/";
注意版本问题 或 是不是未认证。
https://my.oschina.net/gmarshal/blog/2999556
欢迎关注个人我的微信订阅号:(听说这个头像程序猿专用)