From d595c73b172a9c21a7939479c9ec61e17f8d88a8 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Fri, 6 Nov 2020 17:35:55 +0800 Subject: [PATCH 1/6] 1.pom add the Nacos dependencies; 2.use Nacos to refresh the config; 3.refactor Apollo listener for compatible with Nacos; 4.refactor application.yml file and add related config. --- pom.xml | 12 +++ src/main/java/we/FizzGatewayApplication.java | 4 +- src/main/java/we/config/ApolloConfig.java | 15 +++ .../java/we/config/AppConfigProperties.java | 2 + src/main/java/we/config/SystemConfig.java | 37 ++++++- .../controller/ManagerConfigController.java | 2 + src/main/java/we/filter/PreFilter.java | 3 + src/main/java/we/fizz/ConfigLoader.java | 2 + src/main/java/we/fizz/input/ScriptHelper.java | 4 +- .../java/we/plugin/auth/ApiConfigService.java | 23 ++++- .../java/we/plugin/stat/StatPluginFilter.java | 4 + src/main/resources/application.yml | 97 ++++++++++++++----- 12 files changed, 172 insertions(+), 33 deletions(-) create mode 100644 src/main/java/we/config/ApolloConfig.java diff --git a/pom.xml b/pom.xml index 6f6fd32..ce14ad3 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@ 2.13.3 4.1.53.Final 4.5.13 + 0.2.7 @@ -148,6 +149,17 @@ 2.2.5.RELEASE + + com.alibaba.boot + nacos-config-spring-boot-starter + ${nacos.version} + + + com.alibaba.boot + nacos-discovery-spring-boot-starter + ${nacos.version} + + org.apache.commons commons-pool2 diff --git a/src/main/java/we/FizzGatewayApplication.java b/src/main/java/we/FizzGatewayApplication.java index 319b5ed..25d46ae 100644 --- a/src/main/java/we/FizzGatewayApplication.java +++ b/src/main/java/we/FizzGatewayApplication.java @@ -1,6 +1,6 @@ package we; -import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; +import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; @@ -12,7 +12,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; exclude = {ErrorWebFluxAutoConfiguration.class, RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class}, scanBasePackages = {"we"} ) -@EnableApolloConfig +@NacosPropertySource(dataId = "application", groupId = "fizz-gateway", autoRefreshed = true) @EnableDiscoveryClient public class FizzGatewayApplication { diff --git a/src/main/java/we/config/ApolloConfig.java b/src/main/java/we/config/ApolloConfig.java new file mode 100644 index 0000000..f41e8a6 --- /dev/null +++ b/src/main/java/we/config/ApolloConfig.java @@ -0,0 +1,15 @@ +package we.config; + +import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; + +/** + * Apollo config + * @author zhongjie + */ +@ConditionalOnProperty(name = "apollo.enabled") +@EnableApolloConfig +@Configuration +public class ApolloConfig { +} diff --git a/src/main/java/we/config/AppConfigProperties.java b/src/main/java/we/config/AppConfigProperties.java index 5e19b1d..268131c 100644 --- a/src/main/java/we/config/AppConfigProperties.java +++ b/src/main/java/we/config/AppConfigProperties.java @@ -17,6 +17,7 @@ package we.config; +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @@ -27,6 +28,7 @@ import org.springframework.context.annotation.Configuration; @Configuration public class AppConfigProperties { + @NacosValue(value = "${spring.profiles.active}", autoRefreshed = true) @Value("${spring.profiles.active}") private String env; diff --git a/src/main/java/we/config/SystemConfig.java b/src/main/java/we/config/SystemConfig.java index 0d8bab6..4911ff4 100644 --- a/src/main/java/we/config/SystemConfig.java +++ b/src/main/java/we/config/SystemConfig.java @@ -17,10 +17,12 @@ package we.config; +import com.alibaba.nacos.api.config.annotation.NacosValue; import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; +import org.springframework.util.ObjectUtils; import we.plugin.auth.GatewayGroup; import we.util.Constants; import we.util.JacksonUtils; @@ -61,6 +63,7 @@ public class SystemConfig { // // private Set currentServerGatewayGroupSet; + @NacosValue(value = "${spring.profiles.active}") @Value("${spring.profiles.active}") private String profile; @@ -140,11 +143,9 @@ public class SystemConfig { String nv = c.getNewValue(); log.info(p + " old: " + ov + ", new: " + nv); if (p.equals("log.response-body")) { - logResponseBody = Boolean.valueOf(nv); - afterLogResponseBodySet(); + this.updateLogResponseBody(Boolean.parseBoolean(nv)); } else if (p.equals("log.headers")) { - logHeaders = nv; - afterLogHeadersSet(); + this.updateLogHeaders(nv); } /*else if (p.equals("gateway-group")) { gatewayGroup = nv; afterGatewayGroupSet(); @@ -152,4 +153,32 @@ public class SystemConfig { } ); } + + private void updateLogResponseBody(boolean newValue) { + logResponseBody = newValue; + this.afterLogResponseBodySet(); + } + + private void updateLogHeaders(String newValue) { + logHeaders = newValue; + afterLogHeadersSet(); + } + + @NacosValue(value = "${log.response-body:false}", autoRefreshed = true) + public void setLogResponseBody(boolean logResponseBody) { + if (this.logResponseBody == logResponseBody) { + return; + } + log.info("log.response-body old: " + this.logResponseBody + ", new: " + logResponseBody); + this.updateLogResponseBody(logResponseBody); + } + + @NacosValue(value = "${log.headers:x}", autoRefreshed = true) + public void setLogHeaders(String logHeaders) { + if (ObjectUtils.nullSafeEquals(this.logHeaders, logHeaders)) { + return; + } + log.info("log.headers old: " + this.logHeaders + ", new: " + logHeaders); + this.updateLogHeaders(logHeaders); + } } diff --git a/src/main/java/we/controller/ManagerConfigController.java b/src/main/java/we/controller/ManagerConfigController.java index 92fa2f3..eb2929b 100644 --- a/src/main/java/we/controller/ManagerConfigController.java +++ b/src/main/java/we/controller/ManagerConfigController.java @@ -17,6 +17,7 @@ package we.controller; +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PostMapping; @@ -44,6 +45,7 @@ import java.util.stream.Collectors; @RestController @RequestMapping(value = "/managerConfig") public class ManagerConfigController { + @NacosValue(value = "${fizz.manager.config.key:fizz-manager-key}", autoRefreshed = true) @Value("${fizz.manager.config.key:fizz-manager-key}") private String key; diff --git a/src/main/java/we/filter/PreFilter.java b/src/main/java/we/filter/PreFilter.java index 1e2241e..7d7dcc1 100644 --- a/src/main/java/we/filter/PreFilter.java +++ b/src/main/java/we/filter/PreFilter.java @@ -17,6 +17,7 @@ package we.filter; +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,9 +57,11 @@ public class PreFilter extends ProxyAggrFilter { private static final FilterResult succFr = FilterResult.SUCCESS(PRE_FILTER); + @NacosValue(value = "${spring.profiles.active}") @Value("${spring.profiles.active}") private String profile; + @NacosValue(value = "${b-services:x}") @Value("${b-services:x}") private Set bServices = new HashSet<>(); diff --git a/src/main/java/we/fizz/ConfigLoader.java b/src/main/java/we/fizz/ConfigLoader.java index e8a661c..81254a9 100644 --- a/src/main/java/we/fizz/ConfigLoader.java +++ b/src/main/java/we/fizz/ConfigLoader.java @@ -20,6 +20,7 @@ package we.fizz; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; +import com.alibaba.nacos.api.config.annotation.NacosValue; import we.config.AppConfigProperties; import we.fizz.input.ClientInputConfig; import we.fizz.input.Input; @@ -69,6 +70,7 @@ public class ConfigLoader { @Resource(name = AGGREGATE_REACTIVE_REDIS_TEMPLATE) private ReactiveStringRedisTemplate reactiveStringRedisTemplate; + @NacosValue(value = "${fizz.aggregate.read-local-config-flag:false}", autoRefreshed = true) @Value("${fizz.aggregate.read-local-config-flag:false}") private Boolean readLocalConfigFlag; diff --git a/src/main/java/we/fizz/input/ScriptHelper.java b/src/main/java/we/fizz/input/ScriptHelper.java index a6644d9..eee3aa8 100644 --- a/src/main/java/we/fizz/input/ScriptHelper.java +++ b/src/main/java/we/fizz/input/ScriptHelper.java @@ -29,7 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSON; -import com.ctrip.framework.apollo.core.utils.StringUtils; +import org.springframework.util.StringUtils; import we.constants.CommonConstants; import we.exception.StopAndResponseException; @@ -57,7 +57,7 @@ public class ScriptHelper { Script script = new Script(); script.setType((String) scriptCfg.get("type")); script.setSource((String) scriptCfg.get("source")); - if (StringUtils.isBlank(script.getType()) || StringUtils.isBlank(script.getSource())) { + if (!StringUtils.hasText(script.getType()) || !StringUtils.hasText(script.getSource())) { return null; } diff --git a/src/main/java/we/plugin/auth/ApiConfigService.java b/src/main/java/we/plugin/auth/ApiConfigService.java index 84751f4..31e6b8d 100644 --- a/src/main/java/we/plugin/auth/ApiConfigService.java +++ b/src/main/java/we/plugin/auth/ApiConfigService.java @@ -17,6 +17,7 @@ package we.plugin.auth; +import com.alibaba.nacos.api.config.annotation.NacosValue; import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; @@ -30,6 +31,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -75,13 +77,26 @@ public class ApiConfigService { k -> { ConfigChange cc = cce.getChange(k); if (cc.getPropertyName().equalsIgnoreCase("serviceWhiteList")) { - log.info("old service white list: " + cc.getOldValue()); - serviceWhiteList = cc.getNewValue(); - afterServiceWhiteListSet(); + this.updateServiceWhiteList(cc.getOldValue(), cc.getNewValue()); } } ); } + + private void updateServiceWhiteList(String oldValue, String newValue) { + if (ObjectUtils.nullSafeEquals(oldValue, newValue)) { + return; + } + log.info("old service white list: " + oldValue); + serviceWhiteList = newValue; + afterServiceWhiteListSet(); + } + + @NacosValue(value = "${serviceWhiteList:x}", autoRefreshed = true) + public void setServiceWhiteList(String serviceWhiteList) { + this.updateServiceWhiteList(this.serviceWhiteList, serviceWhiteList); + } + public void afterServiceWhiteListSet() { if (StringUtils.isNotBlank(serviceWhiteList)) { whiteListSet.clear(); @@ -94,6 +109,7 @@ public class ApiConfigService { } } + @NacosValue(value = "${auth.compatible-wh:false}", autoRefreshed = true) @Value("${auth.compatible-wh:false}") private boolean compatibleWh; @@ -109,6 +125,7 @@ public class ApiConfigService { @Autowired(required = false) private CustomAuth customAuth; + @NacosValue(value = "${openServiceWhiteList:false}", autoRefreshed = true) @Value("${openServiceWhiteList:false}") private boolean openServiceWhiteList = false; diff --git a/src/main/java/we/plugin/stat/StatPluginFilter.java b/src/main/java/we/plugin/stat/StatPluginFilter.java index a314537..8eb25d6 100644 --- a/src/main/java/we/plugin/stat/StatPluginFilter.java +++ b/src/main/java/we/plugin/stat/StatPluginFilter.java @@ -17,6 +17,7 @@ package we.plugin.stat; +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,12 +64,15 @@ public class StatPluginFilter extends PluginFilter { private static final String reqTime = "\"reqTime\":"; + @NacosValue(value = "${stat.open:false}", autoRefreshed = true) @Value("${stat.open:false}") private boolean statOpen = false; + @NacosValue(value = "${stat.channel:fizz_access_stat}", autoRefreshed = true) @Value("${stat.channel:fizz_access_stat}") private String fizzAccessStatChannel; + @NacosValue(value = "${stat.topic:}", autoRefreshed = true) @Value("${stat.topic:}") private String fizzAccessStatTopic; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index eaa6ac7..365f21e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,27 +1,80 @@ -#apollo: -# bootstrap: -# enabled: true -# namespaces: application -# eagerLoad: -# enabled: true +# if you do not use Apollo, ignore the follow config +######################### Apollo config start ##################################### +apollo: + # if use Apollo set this flag to true + enabled: false + bootstrap: + # if use Apollo set this flag to true + enabled: false + namespaces: application + eagerLoad: + # if use Apollo set this flag to true + enabled: false +######################### Apollo config end ####################################### -spring.profiles.active: dev +# if you do not use Nacos, ignore the follow config +######################### Nacos config start ###################################### +nacos: + config: + # if use Nacos config set this flag to true + enabled: false + # need replace + server-addr: localhost:8848 + auto-refresh: true + group: fizz-gateway + data-id: application + type: PROPERTIES + # need replace + namespace: c37ecd3b-e8b3-42cc-ba94-98e931e33683 + discovery: + # if use Nacos discovery set this flag to true + enabled: false + # need replace + server-addr: localhost:8848 + auto-register: true +######################### Nacos config end ####################################### -server.port: 8600 +# if you do not use Eureka, ignore the follow config +######################### Eureka config start #################################### +eureka: + client: + # if use Eureka set this flag to true + enabled: false + serviceUrl: + # need replace + defaultZone: http://localhost:6600/eureka/ + instance: + prefer-ip-address: true +######################### Eureka config end ###################################### -eureka.instance.prefer-ip-address: true -eureka.client.serviceUrl.defaultZone: http://localhost:6600/eureka/ -spring.application.name: fizz-gateway -spring.cloud.loadbalancer.ribbon.enabled: false +server: + port: 8600 +spring: + profiles: + active: dev + application: + name: fizz-gateway + cloud: + loadbalancer: + ribbon: + enabled: false -aggregate.redis.host: localhost -aggregate.redis.port: 6379 -aggregate.redis.password: 123456 -aggregate.redis.database: 10 +aggregate: + redis: + # need replace + host: localhost + # need replace + port: 6379 + # need replace + password: 123456 + # need replace + database: 9 +proxy-webclient: + name: proxy +aggr-webclient: + name: aggr +fizz-web-client: + timeout: 20000 +log: + headers: COOKIE,FIZZ-APPID,FIZZ-SECRETKEY,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV -proxy-webclient.name: proxy -aggr-webclient.name: aggr - -fizz-web-client.timeout: 20000 - -log.headers: COOKIE,FIZZ-APPID,FIZZ-SECRETKEY,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV From 8768848d71d062149ae425626957beb6db8e9afd Mon Sep 17 00:00:00 2001 From: linwaiwai Date: Mon, 9 Nov 2020 10:37:35 +0800 Subject: [PATCH 2/6] Create CNAME --- docs/CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/CNAME diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..692ef2e --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +fizzgate.com \ No newline at end of file From 89757b342f9571525b604ed945304c04d2d1a4d5 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Mon, 9 Nov 2020 15:05:05 +0800 Subject: [PATCH 3/6] refactor the hard code with Eureka to support optional Eureka and Nacos. --- .../AbstractDiscoveryClientUriSelector.java | 17 ++++++ .../we/proxy/DisableDiscoveryUriSelector.java | 19 +++++++ .../we/proxy/DiscoveryClientUriSelector.java | 16 ++++++ src/main/java/we/proxy/EurekaUriSelector.java | 55 +++++++++++++++++++ src/main/java/we/proxy/FizzWebClient.java | 43 ++------------- src/main/java/we/proxy/NacosUriSelector.java | 46 ++++++++++++++++ 6 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 src/main/java/we/proxy/AbstractDiscoveryClientUriSelector.java create mode 100644 src/main/java/we/proxy/DisableDiscoveryUriSelector.java create mode 100644 src/main/java/we/proxy/DiscoveryClientUriSelector.java create mode 100644 src/main/java/we/proxy/EurekaUriSelector.java create mode 100644 src/main/java/we/proxy/NacosUriSelector.java diff --git a/src/main/java/we/proxy/AbstractDiscoveryClientUriSelector.java b/src/main/java/we/proxy/AbstractDiscoveryClientUriSelector.java new file mode 100644 index 0000000..94ab1de --- /dev/null +++ b/src/main/java/we/proxy/AbstractDiscoveryClientUriSelector.java @@ -0,0 +1,17 @@ +package we.proxy; + +import we.util.Constants; +import we.util.ThreadContext; + +/** + * Abstract implementation of {@code DiscoveryClientUriSelector} + * + * @author zhongjie + */ +abstract public class AbstractDiscoveryClientUriSelector implements DiscoveryClientUriSelector { + + protected String buildUri(String ipAddr, int port, String path) { + StringBuilder b = ThreadContext.getStringBuilder(); + return b.append(Constants.Symbol.HTTP_PROTOCOL_PREFIX).append(ipAddr).append(Constants.Symbol.COLON).append(port).append(path).toString(); + } +} diff --git a/src/main/java/we/proxy/DisableDiscoveryUriSelector.java b/src/main/java/we/proxy/DisableDiscoveryUriSelector.java new file mode 100644 index 0000000..093225f --- /dev/null +++ b/src/main/java/we/proxy/DisableDiscoveryUriSelector.java @@ -0,0 +1,19 @@ +package we.proxy; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; + +/** + * The disable implementation of {@code DiscoveryClientUriSelector}, used when Nacos and Eureka discovery are not enabled. + * + * @author zhongjie + */ + +@ConditionalOnExpression("${nacos.discovery.enabled} == false and ${eureka.client.enabled} == false") +@Service +public class DisableDiscoveryUriSelector implements DiscoveryClientUriSelector { + @Override + public String getNextUri(String service, String relativeUri) { + throw new RuntimeException("No " + service + " because discovery disabled", null, false, false) {}; + } +} diff --git a/src/main/java/we/proxy/DiscoveryClientUriSelector.java b/src/main/java/we/proxy/DiscoveryClientUriSelector.java new file mode 100644 index 0000000..8d5f326 --- /dev/null +++ b/src/main/java/we/proxy/DiscoveryClientUriSelector.java @@ -0,0 +1,16 @@ +package we.proxy; + +/** + * A {@code DiscoveryClientUriSelector} is used to select the uri for the next request + * + * @author zhongjie + */ +public interface DiscoveryClientUriSelector { + /** + * find a instance of service by discovery and return the uri that http://{instance-ip-addr}:{instance-port}{relativeUri} + * @param service service name + * @param relativeUri relative uri + * @return the uri for the next request + */ + String getNextUri(String service, String relativeUri); +} diff --git a/src/main/java/we/proxy/EurekaUriSelector.java b/src/main/java/we/proxy/EurekaUriSelector.java new file mode 100644 index 0000000..a355549 --- /dev/null +++ b/src/main/java/we/proxy/EurekaUriSelector.java @@ -0,0 +1,55 @@ +package we.proxy; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import com.netflix.discovery.shared.Applications; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * The Eureka implementation of {@code DiscoveryClientUriSelector} + * + * @author zhongjie + */ +@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true) +@Service +public class EurekaUriSelector extends AbstractDiscoveryClientUriSelector { + + @Resource + private EurekaClient eurekaClient; + + @Override + public String getNextUri(String service, String relativeUri) { + InstanceInfo inst = roundRobinChoose1instFrom(service); + return buildUri(inst.getIPAddr(), inst.getPort(), relativeUri); + } + + + // private static List aggrMemberInsts = new ArrayList<>(); + // static { + // InstanceInfo i0 = InstanceInfo.Builder.newBuilder().setAppName("TRIP-MINI").setIPAddr("xxx.25.63.192").setPort(7094).build(); + // aggrMemberInsts.add(i0); + // } + // private static AtomicLong counter = new AtomicLong(0); + // private static final String aggrMember = "trip-mini"; + + + private InstanceInfo roundRobinChoose1instFrom(String service) { + + // if (aggrMember.equals(service)) { + // int idx = (int) (counter.incrementAndGet() % aggrMemberInsts.size()); + // return aggrMemberInsts.get(idx); + // } + + List insts = eurekaClient.getInstancesByVipAddress(service, false); + if (insts == null || insts.isEmpty()) { + throw new RuntimeException("eureka no " + service, null, false, false) {}; + } + Applications apps = eurekaClient.getApplications(); + int index = (int) (apps.getNextIndex(service.toUpperCase(), false).incrementAndGet() % insts.size()); + return insts.get(index); + } +} diff --git a/src/main/java/we/proxy/FizzWebClient.java b/src/main/java/we/proxy/FizzWebClient.java index d1be262..90a550e 100644 --- a/src/main/java/we/proxy/FizzWebClient.java +++ b/src/main/java/we/proxy/FizzWebClient.java @@ -17,10 +17,7 @@ package we.proxy; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import com.netflix.discovery.shared.Applications; - +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -43,10 +40,7 @@ import we.util.WebUtils; import javax.annotation.PostConstruct; import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicLong; /** * @author hongqiaowei @@ -62,7 +56,7 @@ public class FizzWebClient { private static final String localhost = "localhost"; @Resource - private EurekaClient eurekaClient; + private DiscoveryClientUriSelector discoveryClientUriSelector; @Resource(name = ProxyWebClientConfig.proxyWebClient) private WebClient proxyWebClient; @@ -70,6 +64,7 @@ public class FizzWebClient { @Resource(name = AggrWebClientConfig.aggrWebClient) private WebClient aggrWebClient; + @NacosValue(value = "${fizz-web-client.timeout:-1}") @Value("${fizz-web-client.timeout:-1}") private long timeout = -1; @@ -140,8 +135,7 @@ public class FizzWebClient { // what about multiple nginx instance // current - InstanceInfo inst = roundRobinChoose1instFrom(service); - String uri = buildUri(inst, relativeUri); + String uri = discoveryClientUriSelector.getNextUri(service, relativeUri); return send2uri(originReqIdOrBizId, method, uri, headers, body, cbc); } @@ -225,37 +219,8 @@ public class FizzWebClient { // TODO 请求完成后,做metric, 以反哺后续的请求转发 } - private String buildUri(InstanceInfo inst, String path) { - StringBuilder b = ThreadContext.getStringBuilder(); - return b.append(Constants.Symbol.HTTP_PROTOCOL_PREFIX).append(inst.getIPAddr()).append(Constants.Symbol.COLON).append(inst.getPort()).append(path).toString(); - } - // private static List aggrMemberInsts = new ArrayList<>(); - // static { - // InstanceInfo i0 = InstanceInfo.Builder.newBuilder().setAppName("TRIP-MINI").setIPAddr("xxx.25.63.192").setPort(7094).build(); - // aggrMemberInsts.add(i0); - // } - // private static AtomicLong counter = new AtomicLong(0); - // private static final String aggrMember = "trip-mini"; - - - private InstanceInfo roundRobinChoose1instFrom(String service) { - - // if (aggrMember.equals(service)) { - // int idx = (int) (counter.incrementAndGet() % aggrMemberInsts.size()); - // return aggrMemberInsts.get(idx); - // } - - List insts = eurekaClient.getInstancesByVipAddress(service, false); - if (insts == null || insts.isEmpty()) { - throw new RuntimeException("eureka no " + service, null, false, false) {}; - } - Applications apps = eurekaClient.getApplications(); - int index = (int) (apps.getNextIndex(service.toUpperCase(), false).incrementAndGet() % insts.size()); - return insts.get(index); - } - private String extractServiceOrAddress(String uriOrSvc) { return uriOrSvc.substring(7, uriOrSvc.indexOf(Constants.Symbol.FORWARD_SLASH, 10)); } diff --git a/src/main/java/we/proxy/NacosUriSelector.java b/src/main/java/we/proxy/NacosUriSelector.java new file mode 100644 index 0000000..fa785ae --- /dev/null +++ b/src/main/java/we/proxy/NacosUriSelector.java @@ -0,0 +1,46 @@ +package we.proxy; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * The Nacos implementation of {@code DiscoveryClientUriSelector} + * + * @author zhongjie + */ +@ConditionalOnProperty(value = "nacos.discovery.enabled") +@Service +public class NacosUriSelector extends AbstractDiscoveryClientUriSelector { + private static final Logger log = LoggerFactory.getLogger(NacosUriSelector.class); + + @Resource + private NamingService naming; + + @Override + public String getNextUri(String service, String relativeUri) { + Instance instance = this.selectOneHealthyInstance(service); + return super.buildUri(instance.getIp(), instance.getPort(), relativeUri); + } + + private Instance selectOneHealthyInstance(String service) { + Instance instance = null; + try { + instance = naming.selectOneHealthyInstance(service); + } catch (NacosException e) { + log.warn("Nacos selectOneHealthyInstance({}) exception", service, e); + } + + if (instance == null) { + throw new RuntimeException("Nacos no " + service, null, false, false) {}; + } + + return instance; + } +} From 64de533e3b28b16251f5877f08a1eba9d916baf9 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Thu, 12 Nov 2020 14:08:21 +0800 Subject: [PATCH 4/6] refactor the hard code with Eureka to support optional Eureka and Nacos. --- src/main/java/we/proxy/NacosUriSelector.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/we/proxy/NacosUriSelector.java b/src/main/java/we/proxy/NacosUriSelector.java index fa785ae..28eab8c 100644 --- a/src/main/java/we/proxy/NacosUriSelector.java +++ b/src/main/java/we/proxy/NacosUriSelector.java @@ -1,5 +1,6 @@ package we.proxy; +import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; @@ -8,8 +9,6 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; -import javax.annotation.Resource; - /** * The Nacos implementation of {@code DiscoveryClientUriSelector} * @@ -20,7 +19,7 @@ import javax.annotation.Resource; public class NacosUriSelector extends AbstractDiscoveryClientUriSelector { private static final Logger log = LoggerFactory.getLogger(NacosUriSelector.class); - @Resource + @NacosInjected private NamingService naming; @Override From c7e370d8180f1cfc9fc5b263d3a4d604ac8f9c67 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Thu, 12 Nov 2020 14:33:51 +0800 Subject: [PATCH 5/6] application.yml add nacos register group name config. --- src/main/resources/application.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 365f21e..1b0c449 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -32,6 +32,8 @@ nacos: # need replace server-addr: localhost:8848 auto-register: true + register: + group-name: fizz-gateway ######################### Nacos config end ####################################### # if you do not use Eureka, ignore the follow config From 93fa5f9c4607dc1125a483ec4e8bc999f80c34b0 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Tue, 17 Nov 2020 10:36:48 +0800 Subject: [PATCH 6/6] 1.update the nacos uri selector to find the same group instance. 2.update version to 1.2.0. 3.update the readme doc. --- README.md | 20 +++++---- pom.xml | 2 +- sh/boot.sh | 2 +- src/main/java/we/proxy/NacosUriSelector.java | 43 +++++++++++++++++++- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f9041d1..8969457 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ A Managerment API Gateway in Java . Fizz Gateway 是一个基于 Java开发的 | v1.0.0 | v1.0.0 | v1.0.0 | | v1.1.0 | v1.1.0 | v1.1.0 | | v1.1.1 | v1.1.1 | v1.1.1 | +| v1.2.0 | v1.2.0 | v1.1.1 | 请根据社区版的版本下载对应的管理后台版本 @@ -93,13 +94,13 @@ A Managerment API Gateway in Java . Fizz Gateway 是一个基于 Java开发的 ##### 管理后台服务端(fizz-manager-professional) -1. 首次安装执行`fizz-manager-professional-1.1.1-mysql.sql`数据库脚本 -2. 将`application-prod.yml`、`boot.sh`、`fizz-manager-professional-1.1.1.jar`拷贝到`/data/webapps/fizz-manager-professional`目录下 +1. 首次安装执行`fizz-manager-professional-1.2.0-mysql.sql`数据库脚本 +2. 将`application-prod.yml`、`boot.sh`、`fizz-manager-professional-1.2.0.jar`拷贝到`/data/webapps/fizz-manager-professional`目录下 3. 修改`application-prod.yml`文件,将相关配置修改成部署环境的配置 4. 修改`boot.sh`文件,将`RUN_CMD`变量值修改成部署环境的JAVA实际路径 5. 执行 `chmod +x boot.sh` 命令给`boot.sh`增加执行权限 6. 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令 -7. 服务启动后访问 http://IP:8000/fizz-manager (将IP替换成服务部署机器IP地址),使用超级管理员账户`admin`密码`Aa123!`登录 +7. 服务启动后访问前端登录地址,使用超级管理员账户`admin`密码`Aa123!`登录 ##### 管理后台前端(fizz-admin-professional) @@ -126,11 +127,14 @@ server { #### 二、安装fizz-gateway-community社区版 -说明:如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);使用不使用apollo可去掉下面启动命令里的apollo参数。 +说明: + +1. 支持配置中心:apollo、nacos,支持注册中心:eureka、nacos,详细配置方法查看application.yml文件。 +2. 如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);如果不使用apollo可去掉下面启动命令里的apollo参数。 安装方式一:脚本启动: -1. 下载fizz-gateway-community的最新代码,修改application.yml配置文件里eureka、redis的配置,使用maven命令`mvn clean package -DskipTests=true`构建并把构建好的fizz-gateway-community-1.1.1.jar和boot.sh放同一目录 +1. 下载fizz-gateway-community的最新代码,修改application.yml配置文件里配置中心、注册中心、redis的配置,使用maven命令`mvn clean package -DskipTests=true`构建并把构建好的fizz-gateway-community-1.2.0.jar和boot.sh放同一目录 2. 修改boot.sh脚本的apollo连接,JVM内存配置 3. 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令 @@ -138,13 +142,13 @@ server { 1. 本地clone仓库上的最新代码 2. 将项目fizz-gateway导入IDE -3. 导入完成后设置项目启动配置及修改application.yml配置文件里eureka、redis的配置,在VM选项中加入`-Denv=dev -Dapollo.meta=http://localhost:66`(Apollo配置中心地址) +3. 导入完成后设置项目启动配置及修改application.yml配置文件里配置中心、注册中心、redis的配置,在VM选项中加入`-Denv=dev -Dapollo.meta=http://localhost:66`(Apollo配置中心地址) 安装方式三:jar启动: -1. 本地clone仓库上的最新代码,修改application.yml配置文件里eureka、redis的配置 +1. 本地clone仓库上的最新代码,修改application.yml配置文件里配置中心、注册中心、redis的配置 2. 在项目根目录fizz-gateway-community下执行Maven命令`mvn clean package -DskipTests=true`打包 -3. 进入target目录,使用命令`java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.1.1.jar`启动服务 +3. 进入target目录,使用命令`java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.2.0.jar`启动服务 最后访问网关,地址形式为:http://127.0.0.1:8600/proxy/[服务名]/[API Path] diff --git a/pom.xml b/pom.xml index deff66d..691a288 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ we fizz-gateway-community - 1.1.1 + 1.2.0 fizz-gateway-community diff --git a/sh/boot.sh b/sh/boot.sh index 9f0a930..5e6eb48 100644 --- a/sh/boot.sh +++ b/sh/boot.sh @@ -6,7 +6,7 @@ cd `dirname $0` #变量定义 APOLLO_META_SERVER=http://localhost:66 ENV=dev -APP_NAME=fizz-gateway-community-1.1.1.jar +APP_NAME=fizz-gateway-community-1.2.0.jar APP_DEP_DIR=/data/webapps/fizz-gateway APP_LOG_DIR=/data/logs/fizz-gateway JAVA_CMD=/usr/local/java/bin/java diff --git a/src/main/java/we/proxy/NacosUriSelector.java b/src/main/java/we/proxy/NacosUriSelector.java index 28eab8c..fff4144 100644 --- a/src/main/java/we/proxy/NacosUriSelector.java +++ b/src/main/java/we/proxy/NacosUriSelector.java @@ -1,5 +1,7 @@ package we.proxy; +import com.alibaba.boot.nacos.discovery.properties.NacosDiscoveryProperties; +import com.alibaba.boot.nacos.discovery.properties.Register; import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; @@ -8,6 +10,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import java.util.Collections; +import java.util.List; /** * The Nacos implementation of {@code DiscoveryClientUriSelector} @@ -19,8 +26,34 @@ import org.springframework.stereotype.Service; public class NacosUriSelector extends AbstractDiscoveryClientUriSelector { private static final Logger log = LoggerFactory.getLogger(NacosUriSelector.class); + public NacosUriSelector(NacosDiscoveryProperties discoveryProperties) { + this.discoveryProperties = discoveryProperties; + } + @NacosInjected private NamingService naming; + private NacosDiscoveryProperties discoveryProperties; + private String groupName; + private List clusterNameList; + private boolean useGroupName; + private boolean userClusterName; + + @PostConstruct + public void init() { + Register register = discoveryProperties.getRegister(); + if (register != null) { + this.groupName = register.getGroupName(); + if (StringUtils.hasText(groupName)) { + this.useGroupName = true; + } + String clusterName = register.getClusterName(); + if (StringUtils.hasText(clusterName)) { + this.userClusterName = true; + this.clusterNameList = Collections.singletonList(clusterName); + } + + } + } @Override public String getNextUri(String service, String relativeUri) { @@ -31,7 +64,15 @@ public class NacosUriSelector extends AbstractDiscoveryClientUriSelector { private Instance selectOneHealthyInstance(String service) { Instance instance = null; try { - instance = naming.selectOneHealthyInstance(service); + if (useGroupName && userClusterName) { + instance = naming.selectOneHealthyInstance(service, groupName, clusterNameList); + } else if (useGroupName) { + instance = naming.selectOneHealthyInstance(service, groupName); + } else if (userClusterName) { + instance = naming.selectOneHealthyInstance(service, clusterNameList); + } else { + instance = naming.selectOneHealthyInstance(service); + } } catch (NacosException e) { log.warn("Nacos selectOneHealthyInstance({}) exception", service, e); }