【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
pring Cloud Config为分布式系统中的外部化配置提供服务器和客户端支持。
Spring Cloud Config原理
创建Spring Cloud Config 服务端
依赖
<?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.2.2.RELEASE</version>
<relativePath/>
</parent>
<groupId>proj.ms</groupId>
<artifactId>config</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>config</name>
<description>config center</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-monitor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</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-actuator</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>
</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>
配置说明
- spring.cloud.config.server.git 使用Git对配置文件进行管理。uri指定Git仓库地址。
- spring.rabbitmq 使用rabbitmq作为消息队列,用于配置的自动刷新。
添加注解
在启动类上添加@SpringBootApplication、@EnableDiscoveryClient、@EnableConfigServer三个注解:
@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
@ServletComponentScan
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
说明
- @EnableDiscoveryClient 将Spring Cloud Config 服务端作为Eureka的客户端。Spring Cloud Config作为微服务在Eureka中注册,其它服务可通过服务名直接访问配置中心。
- @EnableConfigServer 标识此应用为ConfigServer,启用默认配置。
- @ServletComponentScan 扫描Servlet组件,将自定义过滤器添加至Spring中。
添加配置
spring:
application:
name: config
cloud:
config:
server:
git:
uri: "http://gitlab.figring.com/ms/config.git"
username: "config-center"
password: "W&Yd)R3Vf"
rabbitmq:
host: 192.168.75.130
port: 5672
username: guest
password: guest
eureka:
client:
service-url:
defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/,http://peer3:8763/eureka/
fetch-registry: true
registry-fetch-interval-seconds: 8
instance:
lease-renewal-interval-in-seconds: 4
lease-expiration-duration-in-seconds: 12
server:
port: 8888
management:
endpoints:
web:
exposure:
include: "*"
配置说明
- spring.cloud.config.server.git 使用Git对配置文件进行管理。uri指定Git仓库地址。
- spring.rabbitmq 使用rabbitmq作为消息队列,用于配置的自动刷新。
添加GitLab的Web Hook
在GitLab中添加Spring Cloud Config 服务端配置刷新的回调地址。上述配置文件中配置的GitLab仓库若发生push event,GitLab将调用此地址通知配置中心。配置中心暴露的端点为/actuator/bus-refresh,对应源码中的RefreshBusEndpoint类。
修改GitLab的Web Hook的Request Body
GitLab调用/actuator/bus-refresh端点,在配置中心会发生Json序列化异常。通过拦截bus-refresh端点并进行自定义修改Request Body以达到正常调用的目的。
/**
* 用于拦截bus-refresh端点的请求
*/
@WebFilter(filterName = "BusRefreshFilter", urlPatterns = "/*")
public class BusRefreshFilter implements Filter {
public static final String BUS_REFRESH_ENDPOINT = "/bus-refresh";
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String url = httpServletRequest.getRequestURI();
// 只过滤/bus-refresh端点
if (!url.endsWith(BUS_REFRESH_ENDPOINT)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
//修改Request Body
CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper, servletResponse);
}
@Override
public void destroy() {
}
}
/**
* Request包装类
*/
public class CustometRequestWrapper extends HttpServletRequestWrapper {
public CustometRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() {
byte[] bytes = new byte[0];
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return byteArrayInputStream.read() == -1;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return byteArrayInputStream.read();
}
};
}
}
启动Spring Cloud Config 服务端
启用应用程序。
客户端应用
添加客户端配置文件
在Git仓库中创建user-service-dev.ym文件,添加以下内容:
student:
name: student3
age: 555
spring:
rabbitmq:
host: 192.168.75.130
port: 5672
username: guest
password: guest
客户端依赖
<?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.1.2.RELEASE</version>
<relativePath/>
</parent>
<groupId>proj.ms</groupId>
<artifactId>user-center</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-center</name>
<description>user center</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</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-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</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>
</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>
- 注:客户端需引入spring-cloud-starter-bus-amqp依赖,以便在配置发生变更的时候,通过消息队列获取配置消息。
添加注解
@SpringBootApplication
@EnableDiscoveryClient
public class UserCenterApplication {
public static void main(String[] args) {
SpringApplication.run(UserCenterApplication.class, args);
}
}
添加配置
在resources目录中创建boostrap.yml文件,添加以下内容:
spring:
application:
name: user-service
cloud:
config:
discovery:
enabled: true
service-id: config
profile: dev
eureka:
client:
service-url:
defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/,http://peer3:8763/eureka/
server:
port: 18080
management:
endpoints:
web:
exposure:
include: "*"
- spring.cloud.config.discovery 中service-id指定配置将从名为config的微服务获取。
功能验证
启动user-service微服务,并修改Git仓库中的配置。观察消息队列、配置中心与user-service微服务日志消息队列日志是否正常。
RabbitMQ中消息存在消息生布的消费:
客户端日志,客户端已经重新从配置中心获取的新的配置:
2019-12-24 15:56:32.598 INFO 15408 --- [xuKlDf_RcOW8Q-1] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8888/
2019-12-24 15:56:34.263 INFO 15408 --- [xuKlDf_RcOW8Q-1] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=user-service, profiles=[dev], label=null, version=7ea75c74cc03d422b00403a2b6fbc920ce487d87, state=null
2019-12-24 15:56:34.264 INFO 15408 --- [xuKlDf_RcOW8Q-1] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource {name='configService', propertySources=[MapPropertySource {name='configClient'}, MapPropertySource {name='http://gitlab.figring.com/ms/config.git/user-service-dev.yml'}]}
配置动态刷新测试:
@RestController
@RefreshScope
public class UserController {
@Value("${student.name}")
private String name;
@GetMapping("name")
public String getName() {
return name;
}
}
动态修改配置,访问http://localhost:18080/name ,查看配置是否动态变化。
Spring Cloud Config高可用方案
架构图
Spring Cloud Config Server成为一个普通的微服务,在负载均衡组件的作用下为其它业务相关的微服务提供配置服务。
问题汇总
GitLab调用/actuator/bus-refresh端点时发生Json异常
原因及解决方案见上文。
来源:oschina
链接:https://my.oschina.net/u/649513/blog/3146713