
本篇是上一篇《从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(七) 开发环境使用轻量级在线文档解决知识分享问题》的优化篇

新增两个共通模块mini-cloud-common-gateaway,mini-cloud-balancer ,目录结构如下

mini-cloud-common-gateaway 代码结构以及代码明细,将作为共通被mini-cloud-gateaway 使用
pom.xml dependencies
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-gatewayartifactId>
- dependency>
- <dependency>
- <groupId>javax.servletgroupId>
- <artifactId>javax.servlet-apiartifactId>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-gateway-coreartifactId>
- dependency>
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
- <scope>compilescope>
- dependency>
- <dependency>
- <groupId>cn.hutoolgroupId>
- <artifactId>hutool-allartifactId>
- dependency>
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
- <scope>compilescope>
- dependency>
- <dependency>
- <groupId>org.springframework.securitygroupId>
- <artifactId>spring-security-jwtartifactId>
- dependency>
- <dependency>
- <groupId>com.nimbusdsgroupId>
- <artifactId>nimbus-jose-jwtartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-loadbalancerartifactId>
- dependency>
- dependencies>
EnableMiniCloudRoute.java 主要作为开启引用MiniCloudRouteAutoConfiguration 自定义路由的开关,不然是无法扫描到 MiniCloudRouteAutoConfiguration 类的
- package com.minicloud.common.gateaway.annotation;
-
- import com.minicloud.common.gateaway.config.MiniCloudRouteAutoConfiguration;
- import org.springframework.context.annotation.Import;
-
- import java.lang.annotation.*;
-
-
- @Target({ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @Import(MiniCloudRouteAutoConfiguration.class)
- public @interface EnableMiniCloudRoute {
- }
MiniCloudRouteAutoConfiguration.java 主要是注入后续源码的扫描包,便于引用项目扫面到
- package com.minicloud.common.gateaway.config;
-
- import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
- import org.springframework.context.annotation.ComponentScan;
- import org.springframework.context.annotation.Configuration;
-
-
- @Configuration
- @ComponentScan("com.minicloud.common.gateaway")
- @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
- public class MiniCloudRouteAutoConfiguration {
- }
MiniCloudLoadBalancerClientConfiguration.java如果是使用 REACTIVE 作为web引擎,则可以初始化
MiniCloudReactiveLoadBalancerClientFilter和 MiniCloudLoadBalancer 两个类MiniCloudReactiveLoadBalancerClientFilter :主要是重写 ReactiveLoadBalancerClientFilter 获取request中的version
VersionMiniCloudLoadBalancer: 主要是获取到version 后获取version 对应lb中的instance
- import com.minicloud.common.gateaway.filter.MiniCloudReactiveLoadBalancerClientFilter;
- import com.minicloud.common.gateaway.rule.MiniCloudLoadBalancer;
- import com.minicloud.common.gateaway.rule.VersionMiniCloudLoadBalancer;
- import org.springframework.boot.autoconfigure.AutoConfigureBefore;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
- import org.springframework.boot.context.properties.EnableConfigurationProperties;
- import org.springframework.cloud.client.discovery.DiscoveryClient;
- import org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration;
- import org.springframework.cloud.gateway.config.LoadBalancerProperties;
- import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
-
- @Configuration
- @EnableConfigurationProperties(LoadBalancerProperties.class)
- @AutoConfigureBefore(GatewayReactiveLoadBalancerClientAutoConfiguration.class)
- @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
- public class MiniCloudLoadBalancerClientConfiguration {
-
- @Bean
- public ReactiveLoadBalancerClientFilter gatewayLoadBalancerClientFilter(MiniCloudLoadBalancer miniCloudLoadBalancer,
- LoadBalancerProperties properties) {
- return new MiniCloudReactiveLoadBalancerClientFilter(properties, miniCloudLoadBalancer);
- }
-
- @Bean
- public MiniCloudLoadBalancer grayLoadBalancer(DiscoveryClient discoveryClient) {
- return new VersionMiniCloudLoadBalancer(discoveryClient);
- }
- }
MiniCloudReactiveLoadBalancerClientFilter.java
- @Slf4j
- public class MiniCloudReactiveLoadBalancerClientFilter extends ReactiveLoadBalancerClientFilter {
- private static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150;
- private LoadBalancerProperties properties;
-
- private MiniCloudLoadBalancer miniCloudLoadBalancer;
-
- public MiniCloudReactiveLoadBalancerClientFilter(LoadBalancerProperties properties, MiniCloudLoadBalancer miniCloudLoadBalancer) {
- super(null, properties);
- this.properties = properties;
- this.miniCloudLoadBalancer = miniCloudLoadBalancer;
- }
-
- @Override
- public int getOrder() {
- return LOAD_BALANCER_CLIENT_FILTER_ORDER;
- }
-
- @Override
- public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) { - URI url = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
- String schemePrefix = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
- if (url == null
- || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
- return chain.filter(exchange);
- }
- // preserve the original url
- ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
-
- if (log.isTraceEnabled()) {
- log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName()
- + " url before: " + url);
- }
-
- return choose(exchange).doOnNext(response -> {
-
- if (!response.hasServer()) {
- throw NotFoundException.create(properties.isUse404(),
- "Unable to find instance for " + url.getHost());
- }
-
- URI uri = exchange.getRequest().getURI();
-
- // if the `lb:
` mechanism was used, use `` as the default, - // if the loadbalancer doesn't provide one.
- String overrideScheme = null;
- if (schemePrefix != null) {
- overrideScheme = url.getScheme();
- }
-
- DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(
- response.getServer(), overrideScheme);
-
- URI requestUrl = LoadBalancerUriTools.reconstructURI(serviceInstance, uri);
-
- if (log.isTraceEnabled()) {
- log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
- }
- exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
- }).then(chain.filter(exchange));
- }
-
- private Mono
> choose(ServerWebExchange exchange) { - URI uri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
- ServiceInstance serviceInstance = miniCloudLoadBalancer.choose(uri.getHost(),exchange.getRequest());
- return Mono.just(new DefaultResponse(serviceInstance));
- }
MiniCloudLoadBalancer
- package com.minicloud.common.gateaway.rule;
-
- import org.springframework.cloud.client.ServiceInstance;
- import org.springframework.http.server.reactive.ServerHttpRequest;
-
-
- public interface MiniCloudLoadBalancer {
-
-
- ServiceInstance choose(String serviceId, ServerHttpRequest request);
- }
VersionMiniCloudLoadBalancer.java
- @Slf4j
- @AllArgsConstructor
- public class VersionMiniCloudLoadBalancer implements MiniCloudLoadBalancer {
- private DiscoveryClient discoveryClient;
-
-
-
- @Override
- public ServiceInstance choose(String serviceId, ServerHttpRequest request) {
- List
instances = discoveryClient.getInstances(serviceId); -
- //注册中心无实例 抛出异常
- if (CollUtil.isEmpty(instances)) {
- log.warn("No instance available for {}", serviceId);
- throw new NotFoundException("No instance available for " + serviceId);
- }
-
- // 获取请求version,无则随机返回可用实例
- String reqVersion = request.getHeaders().getFirst("version");
- if (StrUtil.isBlank(reqVersion)) {
- return instances.get(RandomUtil.randomInt(instances.size()));
- }
-
- // 遍历可以实例元数据,若匹配则返回此实例
- for (ServiceInstance instance : instances) {
- Map
metadata = instance.getMetadata(); - String targetVersion = MapUtil.getStr(metadata, "version");
- if (reqVersion.equalsIgnoreCase(targetVersion)) {
- log.info("gray requst match success :{} {}", reqVersion, instance);
- return instance;
- }
- }
- return instances.get(RandomUtil.randomInt(instances.size()));
- }
- }
mini-cloud-common-balancer 代码结构以及代码明细,将作为共通被各个业务端使用
pom.xml
-
-
-
-
org.mini-cloud -
mini-cloud-common-core -
1.0-SNAPSHOT -
-
-
com.alibaba.cloud -
spring-cloud-starter-alibaba-nacos-discovery -
-
-
io.github.openfeign -
feign-core -
-
spring.factories spring-boot 约定文件,也就是传说的“约定大于配置”
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.minicloud.common.balancer.config.MiniCloudRibbonLoadBalancerConfiguration
MiniCloudRibbonLoadBalancerConfiguration.java主要为了注入bean: MiniCloudRibbonLoadBalancerRule ,RequestInterceptor
-
-
- import com.minicloud.common.balancer.fegin.MiniCloudFeignRequestInterceptor;
- import com.minicloud.common.balancer.rule.MiniCloudRibbonLoadBalancerRule;
- import feign.RequestInterceptor;
- import org.springframework.beans.factory.config.ConfigurableBeanFactory;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.Scope;
-
-
- @Configuration
- public class MiniCloudRibbonLoadBalancerConfiguration {
-
- @Bean
- @ConditionalOnMissingBean
- @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public MiniCloudRibbonLoadBalancerRule ribbonLoadBalancerRule() {
- return new MiniCloudRibbonLoadBalancerRule();
- }
-
- @Bean
- public RequestInterceptor grayFeignRequestInterceptor() {
- return new MiniCloudFeignRequestInterceptor();
- }
- }
MiniCloudFeignRequestInterceptor.java 为了拦截fegin请求并设置上游发来的 version
-
- @Slf4j
- public class MiniCloudFeignRequestInterceptor implements RequestInterceptor {
-
-
- @Override
- public void apply(RequestTemplate template) {
- String reqVersion = WebUtils.getRequest() != null
- ? WebUtils.getRequest().getHeader("version") : null;
-
- if (StrUtil.isNotBlank(reqVersion)) {
- log.debug("feign gray add header version :{}", reqVersion);
- template.header("version", reqVersion);
- }
- }
MiniCloudRibbonLoadBalancerRule.java 自定义使用端ribbon loadbalance 路由
-
- @Slf4j
- public class MiniCloudRibbonLoadBalancerRule extends AbstractLoadBalancerRule {
- @Override
- public void initWithNiwsConfig(IClientConfig iClientConfig) {
- }
-
- @Override
- public Server choose(Object key) {
- return choose(getLoadBalancer(), key);
- }
-
-
- public Server choose(ILoadBalancer lb, Object key) {
- List
reachableServers = lb.getReachableServers(); -
- //注册中心无可用实例 抛出异常
- if (CollUtil.isEmpty(reachableServers)) {
- log.warn("No instance available for {}", key);
- return null;
- }
-
- // 获取请求version,无则随机返回可用实例
- String reqVersion = WebUtils.getRequest() != null
- ? WebUtils.getRequest().getHeader("version") : null;
- if (StrUtil.isBlank(reqVersion)) {
- return reachableServers.get(RandomUtil.randomInt(reachableServers.size()));
- }
-
- // 遍历可以实例元数据,若匹配则返回此实例
- for (Server server : reachableServers) {
- NacosServer nacosServer = (NacosServer) server;
- Map
metadata = nacosServer.getMetadata(); - String targetVersion = MapUtil.getStr(metadata,"version");
- if (reqVersion.equalsIgnoreCase(targetVersion)) {
- log.debug("gray requst match success :{} {}", reqVersion, nacosServer);
- return nacosServer;
- }
- }
- return reachableServers.get(RandomUtil.randomInt(reachableServers.size()));
- }
-
- }