parent
be0adc0a8e
commit
35253be77d
@ -0,0 +1,47 @@ |
||||
# 使用eureka |
||||
|
||||
## 修改网关 |
||||
|
||||
- 打开`/sop-gateway/pom.xml` |
||||
|
||||
添加依赖: |
||||
|
||||
```xml |
||||
<dependency> |
||||
<groupId>org.springframework.cloud</groupId> |
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> |
||||
</dependency> |
||||
``` |
||||
|
||||
- 打开sop-gateway下`application-dev.properties` |
||||
|
||||
注释nacos配置 |
||||
|
||||
```properties |
||||
# nacos cloud配置 |
||||
#spring.cloud.nacos.discovery.server-addr=${nacos.url} |
||||
#nacos.config.server-addr=${nacos.url} |
||||
``` |
||||
|
||||
添加eureka配置 |
||||
|
||||
```properties |
||||
# eureka注册中心 |
||||
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ |
||||
``` |
||||
|
||||
## 微服务端修改 |
||||
|
||||
步骤同上 |
||||
|
||||
## admin修改 |
||||
|
||||
打开`application-dev.properties`,新增配置 |
||||
|
||||
```properties |
||||
# eureka注册中心 |
||||
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ |
||||
# 如果使用eureka,填eureka,使用nacos,填eureka |
||||
registry.name=eureka |
||||
``` |
||||
|
@ -0,0 +1,14 @@ |
||||
package com.gitee.sop.adminserver.service.impl; |
||||
|
||||
import lombok.Data; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
@Data |
||||
public class EurekaApplication { |
||||
private String name; |
||||
private List<EurekaInstance> instance; |
||||
} |
@ -0,0 +1,13 @@ |
||||
package com.gitee.sop.adminserver.service.impl; |
||||
|
||||
import lombok.Data; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
@Data |
||||
public class EurekaApplications { |
||||
private List<EurekaApplication> application; |
||||
} |
@ -0,0 +1,11 @@ |
||||
package com.gitee.sop.adminserver.service.impl; |
||||
|
||||
import lombok.Data; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
@Data |
||||
public class EurekaApps { |
||||
private EurekaApplications applications; |
||||
} |
@ -0,0 +1,70 @@ |
||||
package com.gitee.sop.adminserver.service.impl; |
||||
|
||||
import lombok.Data; |
||||
import org.springframework.util.CollectionUtils; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* { |
||||
* "instance": { |
||||
* "instanceId": "demo-order2:11101", |
||||
* "app": "demo-order2", |
||||
* "appGroutName": null, |
||||
* "ipAddr": "127.0.0.1", |
||||
* "sid": "na", |
||||
* "homePageUrl": null, |
||||
* "statusPageUrl": null, |
||||
* "healthCheckUrl": null, |
||||
* "secureHealthCheckUrl": null, |
||||
* "vipAddress": "demo-order2", |
||||
* "secureVipAddress": "demo-order2", |
||||
* "countryId": 1, |
||||
* "dataCenterInfo": { |
||||
* "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo", |
||||
* "name": "MyOwn" |
||||
* }, |
||||
* "hostName": "127.0.0.1", |
||||
* "status": "UP", |
||||
* "leaseInfo": null, |
||||
* "isCoordinatingDiscoveryServer": false, |
||||
* "lastUpdatedTimestamp": 1529391461000, |
||||
* "lastDirtyTimestamp": 1529391461000, |
||||
* "actionType": null, |
||||
* "asgName": null, |
||||
* "overridden_status": "UNKNOWN", |
||||
* "port": { |
||||
* "$": 11102, |
||||
* "@enabled": "false" |
||||
* }, |
||||
* "securePort": { |
||||
* "$": 7002, |
||||
* "@enabled": "false" |
||||
* }, |
||||
* "metadata": { |
||||
* "@class": "java.util.Collections$EmptyMap" |
||||
* }* } |
||||
* } |
||||
* @author tanghc |
||||
*/ |
||||
@Data |
||||
public class EurekaInstance { |
||||
private String instanceId; |
||||
private String ipAddr; |
||||
private Map<String, Object> port; |
||||
|
||||
private String status; |
||||
private String statusPageUrl; |
||||
private String healthCheckUrl; |
||||
private String lastUpdatedTimestamp; |
||||
|
||||
private Map<String, String> metadata; |
||||
|
||||
public String fetchPort() { |
||||
if (CollectionUtils.isEmpty(port)) { |
||||
return ""; |
||||
} |
||||
return String.valueOf(port.getOrDefault("$", "")); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,84 @@ |
||||
package com.gitee.sop.adminserver.service.impl; |
||||
|
||||
import okhttp3.MediaType; |
||||
import okhttp3.Request; |
||||
import okhttp3.RequestBody; |
||||
import okhttp3.internal.http.HttpMethod; |
||||
|
||||
/** |
||||
* https://github.com/Netflix/eureka/wiki/Eureka-REST-operations
|
||||
* |
||||
* @author tanghc |
||||
*/ |
||||
public enum EurekaUri { |
||||
|
||||
/** |
||||
* 查询所有实例 Query for all instances |
||||
*/ |
||||
QUERY_APPS("GET", "/apps"), |
||||
/** |
||||
* 查询一个实例 |
||||
*/ |
||||
QUERY_INSTANCES("GET", "/instances/%s"), |
||||
/** |
||||
* 下线 Take instance out of service |
||||
*/ |
||||
OFFLINE_SERVICE("PUT", "/apps/%s/%s/status?value=OUT_OF_SERVICE"), |
||||
/** |
||||
* 上线 Move instance back into service (remove override) |
||||
*/ |
||||
ONLINE_SERVICE("DELETE", "/apps/%s/%s/status?value=UP"), |
||||
/** |
||||
* 设置metadata信息 |
||||
* |
||||
* /apps/{appID}/{instanceID}/metadata?key=value |
||||
*/ |
||||
SET_METADATA("PUT", "/apps/%s/%s/metadata?%s=%s") |
||||
; |
||||
public static final String URL_PREFIX = "/"; |
||||
|
||||
String uri; |
||||
String requestMethod; |
||||
|
||||
EurekaUri(String httpMethod, String uri) { |
||||
if (!uri.startsWith(URL_PREFIX)) { |
||||
uri = "/" + uri; |
||||
} |
||||
this.uri = uri; |
||||
this.requestMethod = httpMethod; |
||||
} |
||||
|
||||
public String getUri(String... args) { |
||||
if (args == null || args.length == 0) { |
||||
return uri; |
||||
} |
||||
Object[] param = new Object[args.length]; |
||||
for (int i = 0; i < args.length; i++) { |
||||
param[i] = args[i]; |
||||
} |
||||
return String.format(uri, param); |
||||
} |
||||
|
||||
public Request getRequest(String url, String... args) { |
||||
if (url.endsWith("/")) { |
||||
url = url.substring(0, url.length() - 1); |
||||
} |
||||
String requestUrl = url + getUri(args); |
||||
Request request = this.getBuilder() |
||||
.url(requestUrl) |
||||
.addHeader("Content-Type", "application/json") |
||||
.addHeader("Accept", "application/json") |
||||
.build(); |
||||
return request; |
||||
} |
||||
|
||||
public Request.Builder getBuilder() { |
||||
String method = requestMethod; |
||||
RequestBody requestBody = null; |
||||
if (HttpMethod.requiresRequestBody(method)) { |
||||
MediaType contentType = MediaType.parse("application/json"); |
||||
requestBody = RequestBody.create(contentType, "{}"); |
||||
} |
||||
return new Request.Builder().method(requestMethod, requestBody); |
||||
} |
||||
} |
@ -0,0 +1,94 @@ |
||||
package com.gitee.sop.adminserver.service.impl; |
||||
|
||||
import com.alibaba.fastjson.JSON; |
||||
import com.gitee.sop.adminserver.bean.ServiceInfo; |
||||
import com.gitee.sop.adminserver.bean.ServiceInstance; |
||||
import com.gitee.sop.adminserver.service.RegistryService; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import okhttp3.OkHttpClient; |
||||
import okhttp3.Request; |
||||
import okhttp3.Response; |
||||
import org.apache.commons.lang3.StringUtils; |
||||
import org.apache.commons.lang3.time.DateFormatUtils; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.util.CollectionUtils; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* eureka接口实现 |
||||
* @author tanghc |
||||
*/ |
||||
@Slf4j |
||||
public class RegistryServiceEurekaImpl implements RegistryService { |
||||
|
||||
private OkHttpClient client = new OkHttpClient(); |
||||
|
||||
@Value("${eureka.client.serviceUrl.defaultZone:}") |
||||
private String eurekaUrl; |
||||
|
||||
@Override |
||||
public List<ServiceInfo> listAllService(int pageNo, int pageSize) throws Exception { |
||||
if (StringUtils.isBlank(eurekaUrl)) { |
||||
throw new IllegalArgumentException("未指定eureka.client.serviceUrl.defaultZone参数"); |
||||
} |
||||
String json = this.requestEurekaServer(EurekaUri.QUERY_APPS); |
||||
EurekaApps eurekaApps = JSON.parseObject(json, EurekaApps.class); |
||||
|
||||
List<ServiceInfo> serviceInfoList = new ArrayList<>(); |
||||
List<EurekaApplication> applicationList = eurekaApps.getApplications().getApplication(); |
||||
for (EurekaApplication eurekaApplication : applicationList) { |
||||
ServiceInfo serviceInfo = new ServiceInfo(); |
||||
serviceInfo.setServiceId(eurekaApplication.getName()); |
||||
List<EurekaInstance> instanceList = eurekaApplication.getInstance(); |
||||
if (!CollectionUtils.isEmpty(instanceList)) { |
||||
serviceInfo.setInstances(new ArrayList<>(instanceList.size())); |
||||
for (EurekaInstance eurekaInstance : instanceList) { |
||||
ServiceInstance serviceInstance = new ServiceInstance(); |
||||
serviceInstance.setInstanceId(eurekaInstance.getInstanceId()); |
||||
serviceInstance.setServiceId(serviceInfo.getServiceId()); |
||||
serviceInstance.setIp(eurekaInstance.getIpAddr()); |
||||
serviceInstance.setPort(Integer.valueOf(eurekaInstance.fetchPort())); |
||||
serviceInstance.setStatus(eurekaInstance.getStatus()); |
||||
Date updateTime = new Date(Long.valueOf(eurekaInstance.getLastUpdatedTimestamp())); |
||||
serviceInstance.setUpdateTime(DateFormatUtils.format(updateTime, TIMESTAMP_PATTERN)); |
||||
serviceInstance.setMetadata(eurekaInstance.getMetadata()); |
||||
serviceInfo.getInstances().add(serviceInstance); |
||||
} |
||||
} |
||||
serviceInfoList.add(serviceInfo); |
||||
} |
||||
return serviceInfoList; |
||||
} |
||||
|
||||
@Override |
||||
public void onlineInstance(ServiceInstance serviceInstance) throws Exception { |
||||
this.requestEurekaServer(EurekaUri.ONLINE_SERVICE, serviceInstance.getServiceId(), serviceInstance.getInstanceId()); |
||||
} |
||||
|
||||
@Override |
||||
public void offlineInstance(ServiceInstance serviceInstance) throws Exception { |
||||
this.requestEurekaServer(EurekaUri.OFFLINE_SERVICE, serviceInstance.getServiceId(), serviceInstance.getInstanceId()); |
||||
} |
||||
|
||||
@Override |
||||
public void setMetadata(ServiceInstance serviceInstance, String key, String value) throws Exception { |
||||
this.requestEurekaServer(EurekaUri.SET_METADATA, serviceInstance.getServiceId(), serviceInstance.getInstanceId(), key, value); |
||||
} |
||||
|
||||
private String requestEurekaServer(EurekaUri eurekaUri, String... args) throws IOException { |
||||
Request request = eurekaUri.getRequest(this.eurekaUrl, args); |
||||
Response response = client.newCall(request).execute(); |
||||
if (response.isSuccessful()) { |
||||
return response.body().string(); |
||||
} else { |
||||
log.error("操作失败,url:{}, msg:{}, code:{}", eurekaUri.getUri(args), response.message(), response.code()); |
||||
throw new RuntimeException("操作失败"); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,17 @@ |
||||
package com.gitee.sop.gatewaycommon.bean; |
||||
|
||||
import lombok.Data; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
@Data |
||||
public class InstanceDefinition { |
||||
private String instanceId; |
||||
private String serviceId; |
||||
private String ip; |
||||
private int port; |
||||
private Map<String, String> metadata; |
||||
} |
@ -0,0 +1,16 @@ |
||||
package com.gitee.sop.gatewaycommon.loadbalancer; |
||||
|
||||
import com.netflix.loadbalancer.Server; |
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
public class EurekaEnvironmentServerChooser extends EnvironmentServerChooser { |
||||
@Override |
||||
protected Map<String, String> getMetada(Server server) { |
||||
return ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata(); |
||||
} |
||||
} |
@ -0,0 +1,115 @@ |
||||
package com.gitee.sop.gatewaycommon.manager; |
||||
|
||||
import com.alibaba.fastjson.JSON; |
||||
import com.alibaba.nacos.api.annotation.NacosInjected; |
||||
import com.alibaba.nacos.api.config.ConfigService; |
||||
import com.alibaba.nacos.api.config.listener.AbstractListener; |
||||
import com.alibaba.nacos.api.exception.NacosException; |
||||
import com.gitee.sop.gatewaycommon.bean.ApiConfig; |
||||
import com.gitee.sop.gatewaycommon.bean.ChannelMsg; |
||||
import com.gitee.sop.gatewaycommon.bean.NacosConfigs; |
||||
import com.gitee.sop.gatewaycommon.secret.IsvManager; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
||||
import javax.annotation.PostConstruct; |
||||
|
||||
/** |
||||
* @author tanghc |
||||
*/ |
||||
@Slf4j |
||||
public class NacosEventProcessor { |
||||
|
||||
@NacosInjected |
||||
private ConfigService configService; |
||||
|
||||
@Autowired |
||||
private EnvGrayManager envGrayManager; |
||||
|
||||
@Autowired |
||||
private IPBlacklistManager ipBlacklistManager; |
||||
|
||||
@Autowired |
||||
private IsvManager isvManager; |
||||
|
||||
@Autowired |
||||
private IsvRoutePermissionManager isvRoutePermissionManager; |
||||
|
||||
@Autowired |
||||
private LimitConfigManager limitConfigManager; |
||||
|
||||
@Autowired |
||||
private RouteConfigManager routeConfigManager; |
||||
|
||||
@PostConstruct |
||||
public void after() throws NacosException { |
||||
log.debug("初始化nacos事件监听"); |
||||
initEnvGray(); |
||||
initIPBlack(); |
||||
initIsv(); |
||||
initIsvRoutePermission(); |
||||
initLimitConfig(); |
||||
initRouteConfig(); |
||||
} |
||||
|
||||
private void initEnvGray() throws NacosException { |
||||
configService.addListener(NacosConfigs.DATA_ID_GRAY, NacosConfigs.GROUP_CHANNEL, new AbstractListener() { |
||||
@Override |
||||
public void receiveConfigInfo(String configInfo) { |
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class); |
||||
envGrayManager.process(channelMsg); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void initIPBlack() throws NacosException { |
||||
configService.addListener(NacosConfigs.DATA_ID_IP_BLACKLIST, NacosConfigs.GROUP_CHANNEL, new AbstractListener() { |
||||
@Override |
||||
public void receiveConfigInfo(String configInfo) { |
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class); |
||||
ipBlacklistManager.process(channelMsg); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void initIsv() throws NacosException { |
||||
configService.addListener(NacosConfigs.DATA_ID_ISV, NacosConfigs.GROUP_CHANNEL, new AbstractListener() { |
||||
@Override |
||||
public void receiveConfigInfo(String configInfo) { |
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class); |
||||
isvManager.process(channelMsg); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void initIsvRoutePermission() throws NacosException { |
||||
configService.addListener(NacosConfigs.DATA_ID_ROUTE_PERMISSION, NacosConfigs.GROUP_CHANNEL, new AbstractListener() { |
||||
@Override |
||||
public void receiveConfigInfo(String configInfo) { |
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class); |
||||
isvRoutePermissionManager.process(channelMsg); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void initLimitConfig() throws NacosException { |
||||
configService.addListener(NacosConfigs.DATA_ID_LIMIT_CONFIG, NacosConfigs.GROUP_CHANNEL, new AbstractListener() { |
||||
@Override |
||||
public void receiveConfigInfo(String configInfo) { |
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class); |
||||
limitConfigManager.process(channelMsg); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void initRouteConfig() throws NacosException { |
||||
configService.addListener(NacosConfigs.DATA_ID_ROUTE_CONFIG, NacosConfigs.GROUP_CHANNEL, new AbstractListener() { |
||||
@Override |
||||
public void receiveConfigInfo(String configInfo) { |
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class); |
||||
routeConfigManager.process(channelMsg); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
} |
@ -1,43 +0,0 @@ |
||||
package com.gitee.sop.gatewaycommon.support; |
||||
|
||||
import com.gitee.sop.gatewaycommon.route.EurekaRoutesListener; |
||||
import com.gitee.sop.gatewaycommon.route.RegistryListener; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent; |
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.event.EventListener; |
||||
|
||||
/** |
||||
* eureka注册中心事件监听 |
||||
* @author tanghc |
||||
*/ |
||||
public class EurekaListenerConfiguration { |
||||
|
||||
@Autowired |
||||
private RegistryListener registryListener; |
||||
|
||||
/** |
||||
* 客户端注册触发 |
||||
* @param event |
||||
*/ |
||||
@EventListener |
||||
public void onEurekaInstanceRegisteredEvent(EurekaInstanceRegisteredEvent event) { |
||||
registryListener.onRegister(event); |
||||
} |
||||
|
||||
/** |
||||
* 客户端下线触发 |
||||
* @param event |
||||
*/ |
||||
@EventListener |
||||
public void onEurekaInstanceCanceledEvent(EurekaInstanceCanceledEvent event) { |
||||
registryListener.onDeregister(event); |
||||
} |
||||
|
||||
@Bean |
||||
RegistryListener registryListener() { |
||||
return new EurekaRoutesListener(); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue