Commit b9629d41 by Nepxion

增加全路由功能

parent e38c7baf
......@@ -12,9 +12,13 @@ package com.nepxion.discovery.plugin.framework.configuration;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import com.nepxion.discovery.plugin.framework.context.PluginContainerInitializedHandler;
import com.nepxion.discovery.plugin.framework.context.PluginContextAware;
import com.nepxion.discovery.plugin.framework.controller.PluginRouterController;
import com.nepxion.discovery.plugin.framework.entity.RuleEntity;
import com.nepxion.discovery.plugin.framework.event.PluginPublisher;
import com.nepxion.discovery.plugin.framework.listener.DiscoveryListenerExecutor;
......@@ -24,6 +28,7 @@ import com.nepxion.discovery.plugin.framework.listener.impl.IpAddressFilterRegis
import com.nepxion.discovery.plugin.framework.listener.impl.VersionFilterDiscoveryListener;
@Configuration
@ComponentScan(basePackages = { "com.nepxion.discovery.plugin.framework.controller" })
public class PluginAutoConfiguration {
static {
System.out.println("");
......@@ -40,6 +45,16 @@ public class PluginAutoConfiguration {
}
@Bean
public RestTemplate pluginRestTemplate() {
return new RestTemplate();
}
@Bean
public PluginContainerInitializedHandler pluginContainerInitializedHandler() {
return new PluginContainerInitializedHandler();
}
@Bean
public PluginContextAware pluginContextAware() {
return new PluginContextAware();
}
......@@ -50,6 +65,11 @@ public class PluginAutoConfiguration {
}
@Bean
public PluginRouterController pluginRouterController() {
return new PluginRouterController();
}
@Bean
public RuleEntity ruleEntity() {
return new RuleEntity();
}
......
......@@ -15,8 +15,13 @@ public class PluginConstant {
public static final String SPRING_APPLICATION_DISCOVERY_REMOTE_CONFIG_ENABLED = "spring.application.discovery.remote.config.enabled";
public static final String SPRING_APPLICATION_NAME = "spring.application.name";
public static final String EUREKA_METADATA_VERSION = "eureka.instance.metadataMap.version";
public static final String EUREKA_METADATA_VERSION = "eureka.instance.metadataMap.version";
public static final String SERVICE_ID = "serviceId";
public static final String VERSION = "version";
public static final String METADATA = "metadata";
public static final String HOST = "host";
public static final String PORT = "port";
public static final String INSTANCES = "instances";
public static final String ENCODING_UTF_8 = "UTF-8";
public static final String SEPARATE = ";";
......
package com.nepxion.discovery.plugin.framework.context;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.context.ApplicationListener;
public class PluginContainerInitializedHandler implements ApplicationListener<EmbeddedServletContainerInitializedEvent> {
private int serverPort;
@Override
public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {
serverPort = event.getEmbeddedServletContainer().getPort();
}
public int getPort() {
return serverPort;
}
}
\ No newline at end of file
......@@ -46,4 +46,8 @@ public class PluginContextAware implements ApplicationContextAware {
public static Boolean isRemoteConfigEnabled(Environment environment) {
return environment.getProperty(PluginConstant.SPRING_APPLICATION_DISCOVERY_REMOTE_CONFIG_ENABLED, Boolean.class, Boolean.TRUE);
}
public Environment getEnvironment() {
return environment;
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.framework.controller;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import com.nepxion.discovery.plugin.framework.constant.PluginConstant;
import com.nepxion.discovery.plugin.framework.context.PluginContainerInitializedHandler;
import com.nepxion.discovery.plugin.framework.context.PluginContextAware;
import com.nepxion.discovery.plugin.framework.entity.RouteEntity;
import com.nepxion.discovery.plugin.framework.exception.PluginException;
import com.nepxion.eventbus.util.HostUtil;
@RestController
public class PluginRouterController {
@Autowired
private PluginContainerInitializedHandler pluginContainerInitializedHandler;
@Autowired
private PluginContextAware pluginContextAware;
@Autowired
private RestTemplate pluginRestTemplate;
@Autowired
private DiscoveryClient discoveryClient;
// 获取本地节点可访问其他节点(根据服务名)的实例列表
@RequestMapping(path = "/instances/{serviceId}", method = RequestMethod.GET)
public List<ServiceInstance> instances(@PathVariable(value = "serviceId") String serviceId) {
return getInstanceList(serviceId);
}
// 获取本地节点的路由信息
@RequestMapping(path = "/info", method = RequestMethod.GET)
public RouteEntity info() {
return getRouteEntity();
}
// 获取本地节点可访问其他节点(根据服务名)的路由信息列表
@RequestMapping(path = "/routes/{routeServiceId}", method = RequestMethod.GET)
public List<RouteEntity> routes(@PathVariable(value = "routeServiceId") String routeServiceId) {
return getRouteEntityList(routeServiceId);
}
// 获取指定节点(根据IP和端口)可访问其他节点(根据服务名)的路由信息列表
@RequestMapping(path = "/routes/{routeServiceId}/{routeHost}/{routePort}", method = RequestMethod.GET)
public List<RouteEntity> routes(@PathVariable(value = "routeServiceId") String routeServiceId, @PathVariable(value = "routeHost") String routeHost, @PathVariable(value = "routePort") int routePort) {
return getRouteEntityList(routeServiceId, routeHost, routePort);
}
// 获取全路径的路由信息
@RequestMapping(path = "/routeAll", method = RequestMethod.POST)
public RouteEntity routeAll(@RequestBody String serviceIds) {
return route(serviceIds);
}
public List<ServiceInstance> getInstanceList(String serviceId) {
return discoveryClient.getInstances(serviceId);
}
public RouteEntity getRouteEntity() {
String serviceId = pluginContextAware.getEnvironment().getProperty(PluginConstant.SPRING_APPLICATION_NAME);
String version = pluginContextAware.getEnvironment().getProperty(PluginConstant.EUREKA_METADATA_VERSION);
String host = HostUtil.getLocalhost();
int port = pluginContainerInitializedHandler.getPort();
RouteEntity routeEntity = new RouteEntity();
routeEntity.setServiceId(serviceId);
routeEntity.setVersion(version);
routeEntity.setHost(host);
routeEntity.setPort(port);
return routeEntity;
}
public List<RouteEntity> getRouteEntityList(String routeServiceId) {
List<ServiceInstance> instanceList = null;
try {
instanceList = getInstanceList(routeServiceId);
} catch (Exception e) {
throw new PluginException("Get instance list for serviceId=" + routeServiceId + " failed", e);
}
if (CollectionUtils.isEmpty(instanceList)) {
return null;
}
List<RouteEntity> routeEntityList = new ArrayList<RouteEntity>();
for (ServiceInstance instance : instanceList) {
String serviceId = instance.getServiceId().toLowerCase();
String version = instance.getMetadata().get(PluginConstant.VERSION);
String host = instance.getHost();
int port = instance.getPort();
RouteEntity routeEntity = new RouteEntity();
routeEntity.setServiceId(serviceId);
routeEntity.setVersion(version);
routeEntity.setHost(host);
routeEntity.setPort(port);
routeEntityList.add(routeEntity);
}
return routeEntityList;
}
@SuppressWarnings("unchecked")
public List<RouteEntity> getRouteEntityList(String routeServiceId, String routeHost, int routePort) {
String url = "http://" + routeHost + ":" + routePort + "/" + PluginConstant.INSTANCES + "/" + routeServiceId;
List<Map<String, ?>> instanceList = null;
try {
instanceList = pluginRestTemplate.getForEntity(url, List.class).getBody();
} catch (RestClientException e) {
throw new PluginException("Get instance list for serviceId=" + routeServiceId + " with url=" + url + " failed", e);
}
if (CollectionUtils.isEmpty(instanceList)) {
return null;
}
List<RouteEntity> routeEntityList = new ArrayList<RouteEntity>();
for (Map<String, ?> instance : instanceList) {
String serviceId = instance.get(PluginConstant.SERVICE_ID).toString().toLowerCase();
String version = ((Map<String, String>) instance.get(PluginConstant.METADATA)).get(PluginConstant.VERSION);
String host = instance.get(PluginConstant.HOST).toString();
int port = (int) instance.get(PluginConstant.PORT);
RouteEntity routeEntity = new RouteEntity();
routeEntity.setServiceId(serviceId);
routeEntity.setVersion(version);
routeEntity.setHost(host);
routeEntity.setPort(port);
routeEntityList.add(routeEntity);
}
return routeEntityList;
}
public RouteEntity route(String serviceIds) {
if (StringUtils.isEmpty(serviceIds)) {
throw new PluginException("Service ids is empty");
}
String[] serviceIdArray = null;
try {
serviceIdArray = StringUtils.split(serviceIds, PluginConstant.SEPARATE);
} catch (Exception e) {
throw new PluginException("Service ids must be separated with '" + PluginConstant.SEPARATE + "'", e);
}
RouteEntity firstRouteEntity = getRouteEntity();
HashMap<String, List<RouteEntity>> routeEntityMap = new HashMap<String, List<RouteEntity>>();
String previousServiceId = null;
for (String serviceId : serviceIdArray) {
serviceId = serviceId.toLowerCase().trim();
if (previousServiceId == null) {
routeFirst(firstRouteEntity, serviceId);
retrieveRouteEntityList(routeEntityMap, serviceId).addAll(firstRouteEntity.getChildRouteEntityList());
} else {
List<RouteEntity> routeEntityList = retrieveRouteEntityList(routeEntityMap, previousServiceId);
for (RouteEntity routeEntity : routeEntityList) {
String routeHost = routeEntity.getHost();
int routePort = routeEntity.getPort();
route(routeEntity, serviceId, routeHost, routePort);
retrieveRouteEntityList(routeEntityMap, serviceId).addAll(routeEntity.getChildRouteEntityList());
}
}
previousServiceId = serviceId;
}
return firstRouteEntity;
}
private void routeFirst(RouteEntity routeEntity, String routeServiceId) {
List<RouteEntity> routeEntityList = getRouteEntityList(routeServiceId);
if (CollectionUtils.isNotEmpty(routeEntityList)) {
routeEntity.getChildRouteEntityList().addAll(routeEntityList);
}
}
private void route(RouteEntity routeEntity, String routeServiceId, String routeHost, int routePort) {
List<RouteEntity> routeEntityList = getRouteEntityList(routeServiceId, routeHost, routePort);
if (CollectionUtils.isNotEmpty(routeEntityList)) {
routeEntity.getChildRouteEntityList().addAll(routeEntityList);
}
}
private List<RouteEntity> retrieveRouteEntityList(HashMap<String, List<RouteEntity>> routeEntityMap, String serviceId) {
List<RouteEntity> routeEntityList = routeEntityMap.get(serviceId);
if (routeEntityList == null) {
routeEntityList = new ArrayList<RouteEntity>();
routeEntityMap.put(serviceId, routeEntityList);
}
return routeEntityList;
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.framework.entity;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.nepxion.discovery.plugin.framework.constant.PluginConstant;
public class RouteEntity implements Serializable {
private static final long serialVersionUID = -4480475963615166799L;
private String serviceId;
private String version;
private String host;
private int port;
private List<RouteEntity> childRouteEntityList = new ArrayList<RouteEntity>();
public String getServiceId() {
return serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public List<RouteEntity> getChildRouteEntityList() {
return childRouteEntityList;
}
public void setChildRouteEntityList(List<RouteEntity> childRouteEntityList) {
this.childRouteEntityList = childRouteEntityList;
}
public String toInfo() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[")
.append(PluginConstant.SERVICE_ID).append("=").append(serviceId).append(", ")
.append(PluginConstant.VERSION).append("=").append(version).append(", ")
.append(PluginConstant.HOST).append("=").append(host).append(", ")
.append(PluginConstant.PORT).append("=").append(port)
.append("]");
return stringBuilder.toString();
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public boolean equals(Object object) {
return EqualsBuilder.reflectionEquals(this, object);
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}
\ No newline at end of file
......@@ -13,7 +13,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import com.nepxion.discovery.plugin.example.extension.MyDiscoveryListener;
import com.nepxion.discovery.plugin.example.extension.MyRegisterListener;
......@@ -27,11 +26,6 @@ public class DiscoveryApplication {
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public DiscoveryConfigAdapter discoveryConfigAdapter() {
return new DiscoveryConfigAdapter();
}
......
package com.nepxion.discovery.plugin.example.controller;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.nepxion.discovery.plugin.framework.constant.PluginConstant;
@RestController
public class DiscoveryController {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@Value("${" + PluginConstant.SPRING_APPLICATION_NAME + "}")
private String aServiceId;
@Value("${" + PluginConstant.EUREKA_METADATA_VERSION + "}")
private String aEurekaVersion;
@RequestMapping(path = "/instances", method = RequestMethod.GET)
public List<ServiceInstance> instances() {
return discoveryClient.getInstances("discovery-springcloud-example-b");
}
@RequestMapping(path = "/routes", method = RequestMethod.GET)
@SuppressWarnings("unchecked")
public List<String> routes() {
List<String> routes = new ArrayList<String>();
// 获取B服务的实例列表
List<ServiceInstance> bInstances = instances();
String aInfo = aServiceId.toLowerCase() + "[" + aEurekaVersion + "]";
if (CollectionUtils.isNotEmpty(bInstances)) {
for (ServiceInstance bInstance : bInstances) {
String bServiceId = bInstance.getServiceId().toLowerCase();
String bEurekaVersion = bInstance.getMetadata().get(PluginConstant.VERSION);
String bInfo = bServiceId + "[" + bEurekaVersion + "]";
String bHost = bInstance.getHost();
int bPort = bInstance.getPort();
// 获取C服务的实例列表
List<Map<String, ?>> cInstances = restTemplate.getForEntity("http://" + bHost + ":" + bPort + "/instances", List.class).getBody();
if (CollectionUtils.isNotEmpty(cInstances)) {
for (Map<String, ?> cInstance : cInstances) {
String cServiceId = cInstance.get("serviceId").toString().toLowerCase();
String cEurekaVersion = ((Map<String, String>) cInstance.get("metadata")).get(PluginConstant.VERSION);
String cInfo = cServiceId + "[" + cEurekaVersion + "]";
StringBuilder stringBuilder = new StringBuilder();
routes.add(stringBuilder.append(aInfo).append("->").append(bInfo).append("->").append(cInfo).toString());
}
} else {
StringBuilder stringBuilder = new StringBuilder();
routes.add(stringBuilder.append(aInfo).append("->").append(bInfo).toString());
}
}
} else {
StringBuilder stringBuilder = new StringBuilder();
routes.add(stringBuilder.append(aInfo).toString());
}
return routes;
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.example.controller;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DiscoveryController {
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping(path = "/instances", method = RequestMethod.GET)
public List<ServiceInstance> instances() {
return discoveryClient.getInstances("discovery-springcloud-example-c");
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment