<!-- 服務註冊-客戶端 --> <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
歡迎關注個人我的微信訂閱號:(聽說這個頭像程序猿專用)