灰度发布定义可查看我上一篇文章:基于zuul实现灰度发布
1、创建工程
创建三个工程:分别为:订单、eureka、user-server
(1)order服务
order服务提供方,提供两个服务,端口分别为:8080、8081,配置如下:
server:
port: 8080
eureka:
instance:
metadata-map:
version: v1
client:
service-url:
defaultZone: http://localhost:7900/eureka
spring:
application:
name: order
---
spring:
profiles: 8081
server:
port: 8081
eureka:
instance:
metadata-map: #自定义元数据区
version: v2
order服务为了测试提供一个controller,打印出各自的端口,代表访问到不同的机器。如下:
@SpringBootApplication
@RestController
public class OrderApplication {
@Value("${server.port}")
private String port;
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@RequestMapping
public String test(){
return "port:" + port;
}
}
(2)eureka工程,就是一个普通的eureka server
(3)user-server工程
是另一个服务提供者。
调用关系图:
从图可看出use-server需要调用order服务。在调用接口时候需要实现灰度发布。
pom.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kingdee</groupId>
<artifactId>user-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR11</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.jmnarloch</groupId>
<artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
<version>2.1.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
启动类代码如下:
@SpringBootApplication
@RestController
public class UserServerApplication {
public static void main(String[] args) {
SpringApplication.run(UserServerApplication.class, args);
}
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
@RequestMapping
public String test(){
return "user-server";
}
}
使用切面编程,增加RequestAspect类:
@Aspect
@Component
public class RequestAspect {
@Pointcut("execution(* com.kingdee.userserver.controller..*Controller*.*(..))")
private void anyMehtod() {
}
@Before(value = "anyMehtod()")
public void before(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String version = request.getHeader("version");
// 灰度规则 匹配的地方 查db,redis ====
if (version.trim().equals("v2")) {
RibbonFilterContextHolder.getCurrentContext().add("version", "v2");
} else if (version.trim().equals("v1")) {
RibbonFilterContextHolder.getCurrentContext().add("version", "v1");
}
}
}
此时可看出被调用服务是需要配置元数据,可查看order的yml配置(order其实就是普通的一个基础服务,order其他配置可查看我的上一篇:基于zuul实现的灰度发布):
server:
port: 8080
eureka:
instance:
metadata-map:
version: v1
client:
service-url:
defaultZone: http://localhost:7900/eureka
spring:
application:
name: server-order
---
spring:
profiles: 8081
server:
port: 8081
eureka:
instance:
metadata-map:
version: v2
controller类:
@RestController
@RequestMapping("/test")
public class TestCallOrderController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/call")
public String testCall() {
ResponseEntity<String> forEntity = restTemplate.getForEntity("http://SERVER-ORDER/order/getPort", String.class);
String body = forEntity.getBody();
return body;
}
}
yml配置文件:
server:
port: 8001
eureka:
client:
service-url:
defaultZone: http://localhost:7900/eureka
spring:
application:
name: user-server
2、测试
使用http://localhost:8001/test/call访问order接口,且在header上配置version=v2,则系统会永远只访问order服务元数据配置了version: v2的服务,如果header中的version配置成v1,则只访问order服务元数据配置了version: v1的服务,其他情况则使用默认的负载均衡规则(轮询)。
如果有问题,欢迎大家留言,一起探讨,一起进步。