Skip to main content

单体项目改造微服务

单体项目改造微服务

  • 单体项目改造微服务

使用nacos模块/使用Nacos服务端

  1. docker安装个nacos服务端
  2. 本地搭建nacos服务端

项目接入nacos客户端/注册服务

pom.xml

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>兼容的版本</version>
</dependency>

application.yml

spring:
application:
name: home-care #服务名称 必须

cloud:
nacos:
server-addr: @nacos.server@
username: @nacos.username@
password: @nacos.password@
discovery:
group: @nacos.discovery.group@ # 注意:官方默认是 DEFAULT_GROUP,不是 DEFAULT
enabled: true # 是否启用服务发现
  • nacos管理端就能看到开了多少应用了

引入gateway模块

pom.xml


<!--project-->
<dependencies>

<!-- SpringCloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>兼容的版本</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>兼容的版本</version>
</dependency>

<!-- Resilience4j 熔断支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
<version>兼容的版本</version>
</dependency>

<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>兼容的版本</version>
</dependency>

</dependencies>

application.yml

server:
port: 8001

spring:
application:
name: ruoyi-gateway
profiles:
active: dev
cloud:
gateway:
discovery:
locator:
# 开启服务发现
enabled: true
# 服务名小写
lower-case-service-id: true
routes:
# 服务
- id: service1
uri: lb://service1 #为服务service1开启负载均衡
predicates:
- Path=/service1/** #以/service1/开头的请求发送到lb://service1
filters:
- StripPrefix=1 #去掉路径中的第一个路径参数" /service1/user/1"=>"/user/1"
- name: CircuitBreaker
args:
name: userServiceCircuitBreaker
fallbackUri: forward:/fallback/user # 熔断降级返回默认错误-服务繁忙
nacos:
# nacos 服务地址
server-addr: @nacos.server@
username: @nacos.username@
password: @nacos.password@
discovery:
# 是否启用服务发现
enabled: true
# 注册组
group: @nacos.discovery.group@
# 命名空间(留空表示public命名空间)
# namespace:
# 心跳间隔
heart-beat-interval: 5000
# 心跳超时
heart-beat-timeout: 15000



熔断默认处理

@RestController
public class FallbackController {

@GetMapping("/fallback/user")
public ResponseEntity<Map<String, Object>> userFallback() {
Map<String, Object> resp = new HashMap<>();
resp.put("code", 503);
resp.put("msg", "用户服务暂时不可用,请稍后重试");
resp.put("data", null);

// 返回和原接口结构兼容的数据(重要!)
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(resp);
}
}
  • 就可以通过网关端口访问服务了
  • 后面可在网关添加 认证鉴权/日志记录/黑白名单/限流防刷/熔断降级/协议转换与适配/跨域处理/请求/响应修改 等功能

其他配置

@Component
public class WebCorsFilter implements WebFilter, Ordered {

/**
* 这里为支持的请求头,如果有自定义的header字段请自己添加
*/
private static final String ALLOWED_HEADERS =
"X-Requested-With, Content-Language, Content-Type, " +
"Authorization, clientid, credential, X-XSRF-TOKEN, " +
"isToken, token, Admin-Token, App-Token, Encrypt-Key, isEncrypt";

/**
* 允许的请求方法
*/
private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";

/**
* 允许的请求来源,使用 * 表示允许任何来源
*/
private static final String ALLOWED_ORIGIN = "*";

/**
* 允许前端访问的响应头,使用 * 表示允许任何响应头
*/
private static final String ALLOWED_EXPOSE = "*";

/**
* 预检请求的缓存时间,单位为秒(此处设置为 5 小时)
*/
private static final String MAX_AGE = "18000L";

/**
* 实现跨域配置的 Web 过滤器
*
* @param exchange ServerWebExchange 对象,表示一次 Web 交换
* @param chain WebFilterChain 对象,表示一组 Web 过滤器链
* @return Mono<Void> 表示异步的过滤器链处理结果
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 判断请求是否为跨域请求
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Credentials", "true");
// 处理预检请求的 OPTIONS 方法,直接返回成功状态码
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(exchange);
}

@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
@Slf4j
@Component
public class WebI18nFilter implements WebFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String language = exchange.getRequest().getHeaders().getFirst("content-language");
Locale locale = Locale.getDefault();
if (language != null && language.length() > 0) {
String[] split = language.split("_");
locale = new Locale(split[0], split[1]);
}
LocaleContextHolder.setLocaleContext(new SimpleLocaleContext(locale), true);
return chain.filter(exchange);
}

@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}

}