目录
一、Spring Cloud Config
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloudconfig ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是configclient。
Config Server是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用Git存储配置文件内容,也可以使用SVN存储,或者是本地文件存储。
Config Client是Config Server的客户端,用于操作存储在Config Server中的配置内容。微服务在启动时会请求Config Server获取配置文件的内容,请求到后再启动容。
详细内容看在线文档:https://springcloud.cc/spring-cloud-config.html。
二、配置服务端
2.1 创建配置中心微服务
2.2 添加依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>leyou</artifactId>
<groupId>com.leyou.parent</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.leyou.config</groupId>
<artifactId>leyou-config</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
</project>
2.3 创建启动类
package com.leyou.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
/**
* @Author: 98050
* @Time: 2018-11-28 16:39
* @Feature: 配置中心
*/
@EnableConfigServer
@SpringBootApplication
public class LyConfigApplication {
public static void main(String[] args) {
SpringApplication.run(LyConfigApplication.class,args);
}
}
2.4 编写配置文件
server:
port: 10011
spring:
application:
name: leyou-config
cloud:
config:
server:
git:
uri: https://github.com/lyj8330328/leyou-config.git
2.5 创建Git仓库
创建配置仓库,上传一个配置文件,注意命名规则:
{application}-{profile}.yml或{application}-{profile}.properties
application为应用名称 profile指的开发环境(用于区分开发环境,测试环境、生产环境等)
然后通过http://localhost:10011/{application}-{profile}.yml查看配置文件。
上传评论微服务的配置文件。
三、配置客户端
修改评论微服务
3.1 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
3.2 修改配置文件
添加bootstrap.yml ,删除application.yml
spring:
cloud:
config:
name: comments
profile: dev
label: master
uri: http://127.0.0.1:10011
3.3 测试
重新启动微服务看是否能正常运行。
先启动配置中心,然后启动注册中,最后启动其它服务。
四、消息总线组件
4.1 简介
如果更新GitHub中的配置文件,那客户端工程是否可以及时接受新的配置信息呢?实际情况是,修改服务器中的配置并没有立刻更新到工程,只有重新启动程序才会读取配置。 那如果想在不重启微服务的情况下更新配置如何来实现呢? 那么就需要使用SpringCloudBus来实现配置的自动更新。集成好的消息队列。
4.2 代码实现
4.2.1 配置服务端(leyou-config)
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
修改配置文件
配置rabbitmq,暴露触发消息总线的地址
server:
port: 10011
spring:
application:
name: leyou-config
cloud:
config:
server:
git:
uri: https://github.com/lyj8330328/leyou-config.git
rabbitmq:
host: 192.168.19.121
username: /leyou
password: leyou
virtual-host: /leyou
management: #暴露触发消息总线的地址
endpoints:
web:
exposure:
include: bus-refresh
4.2.2 配置客户端
修改评论微服务
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
Git中的配置文件增加rabbitmq的地址
Postman测试
发送消息到rabbitmq
Url: http://127.0.0.1:10011/actuator/bus-refresh
Method: post
查看rabbitmq:
4.2.3 自定义配置的读取
在评论微服务的配置当中有自定义属性:
修改IdWorkerProperties类
修改JwtProperties类
修改IdWorkerConfig类
修改MvcConfig类
4.2.4 乐优配置集中管理
(1)将每一个工程的配置文件提取出来,重新命名
(2)上传到GitHub
(3)修改每一个微服务工程,pom.xml中添加依赖
<!--配置管理依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
(4)删除每一个微服务的application.yml
(5)为每一个微服务添加bootstrap.yml
五、创建Webhooks
5.1 设置webhook
在leyou-config仓库中添加webhook
这里面的Payload URL中要填写请求地址,但是肯定不能写http://127.0.0.1:10011/actuator/bus-refresh,需要将本地端口暴露出去。
5.2 暴露本地端口到Internet
使用Sunny-Ngrok进行内网穿透,地址:https://www.ngrok.cc/,具体看里面教程。
当成功暴露端口后,测试webhook。会发现报错404。
原因分析:
GitHub在进行post请求的同时默认会在body加上一串载荷,但是本地服务无法反序列化这段载荷,所以报错。
解决思路:
将原来body清空,使用过滤器。
5.3 设置过滤器
Servlet为我们提供了一个HttpServletRequestMapper的包装类,通过继承该类重写getInputStream方法返回自己构造的ServletInputStream即可达到修改request中body内容的目的。
package come.leyou.config.filter;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
* @author 98050
*/
public class CustometRequestWrapper extends HttpServletRequestWrapper {
public CustometRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
byte[] bytes = new byte[0];
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return byteArrayInputStream.read() == -1 ? true:false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
}
}
设置过滤器
package come.leyou.config.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Author: 98050
* @Time: 2018-11-30 20:59
* @Feature:
*/
public class MyFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(MyFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器启动");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
String url = httpServletRequest.getRequestURI();
//过滤/actuator/bus-refresh请求
String suffix = "/bus-refresh";
if (!url.endsWith(suffix)){
filterChain.doFilter(servletRequest,servletResponse);
return;
}
CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper,servletResponse);
}
@Override
public void destroy() {
logger.info("过滤器销毁");
}
}
配置过滤器
package com.leyou.config.myconfig;
import come.leyou.config.filter.MyFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author: 98050
* @Time: 2018-11-30 20:56
* @Feature:
*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean someFilterRegistration1() {
//新建过滤器注册类
FilterRegistrationBean registration = new FilterRegistrationBean();
// 添加我们写好的过滤器
registration.setFilter( new MyFilter());
// 设置过滤器的URL模式
registration.addUrlPatterns("/*");
return registration;
}
}
测试
问题:
因为使用的是免费的穿透,所以可能不稳定,需要手动deliver。