SpringCloud(九)——统一配置刷新(自动刷新)
前言
在前几篇笔记中记录了统一配置中心的便捷刷新,总结来说是通过一些组件及第三方工具的帮助,然后再向统一配置服务发送POST
请求的方式来完成刷新,虽然和以往相比要方便很多,但是依旧需要我们自行发送请求,如果统一配置中心也有多个节点,那么修改配置文件的操作将会变得更复杂,根据以往的操作方式并没有太好的办法。
所以,git为我们提供了一个组件——webhooks
,该组件是将远端仓库的配置文件发生更改作为一个触发机制,然后执行发送请求的操作,恰巧的是该请求也是POST
方式。
webhooks配置
webhooks是git中提供的一个工具,在对应的仓库中点击管理,然后在左侧边栏的下方找到WebHooks
,点击进去可以看到如下界面:
接下来点击右上角添加WebHooks,可以看到以下界面:
**【注】:**到这里需要停一下,在之前给统一配置中心发送POST
请求的时候,我们使用的是:localhost:${post}/actuator/busrefresh
,可是git作为一个远端版本控制仓库,它无法识别我们所谓的localhost
。如果想要其他服务器可以访问到我们本机电脑则需要一个公网IP。
这时候可以使用内网穿透来将自己的本机地址转化为一个公网IP,这里给大家提供一个免费的内网穿透软件——natapp。
natapp配置步骤
- 免费注册
- 接下来就是常规的注册步骤,在此不做赘述。但是一定要做实名认证,这种网络相关的工具和插件现在必须进行实名认证。
- 实名认证结束后可以点击购买隧道(什么是隧道总结里说),在购买隧道里仅仅需要配置一个自己记得住的隧道名即可,其余的配置都可以后期更改。
- 购买结束后,可以在我的隧道里面看到对应的隧道:
- 点击配置可以看到隧道的详细配置,暂时使用的仅仅是本地地址和本地端口,与统一配置中心的路径相同。
- 然后在官网中下载对应的
natapp
客户端,根据自己的电脑系统选择下载,在此不做赘述。 - 下载成功后将文件放在全英文路径下,然后配置对应的成员变量,如下所示:
- 在
cmd
命令提示符窗口中启动该软件,在此之前要复制一下隧道列表中的authtoken
,然后输入一下命令:
natapp -authtoken=${复制好的authtoken}
- 启动后的页面中会显示为我们转化过后的IP:
PS:图中马赛克部分就是转化后的IP,注意该IP表示的是:localhost:8091
,即在此发送请求的时候不需要加入端口号。
- 在WebHooks界面中把转化后的IP写入,并下图操作:
- 在我们点击添加后,会发现发送的请求出现400错误,这时需要通过在统一配置中心添加过滤器来操作(具体原因是复杂数据类型的JSON与String转化问题,下面提供给大家过滤器的代码):
@Component
public class UrlFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
String url = new String(httpServletRequest.getRequestURI());
//只过滤/actuator/busrefresh请求
// 如果使用的SpringCloud为20版本之前则需要将该字符串修改为 : /bus-refresh
if (!url.endsWith("/busrefresh")) {
chain.doFilter(request, response);
return;
}
//获取原始的body
String body = readAsChars(httpServletRequest);
System.out.println("original body: "+ body);
//使用HttpServletRequest包装原始请求达到修改post请求中body内容的目的
CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
chain.doFilter(requestWrapper, response);
}
@Override
public void destroy() {
}
private 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();
}
};
}
}
public static String readAsChars(HttpServletRequest request)
{
BufferedReader br = null;
StringBuilder sb = new StringBuilder("");
try
{
br = request.getReader();
String str;
while ((str = br.readLine()) != null)
{
sb.append(str);
}
br.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (null != br)
{
try
{
br.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
return sb.toString();
}
}
添加过滤器后在入口类添加可以识别该过滤器的注解
@ServletComponentScan(basePackages = "com.xxx.filters")
- 重启服务过后可以重新测试WebHooks。
总结
所谓隧道,可以单纯的理解为一个URL与对应转化公网IP的沟通桥梁,这种沟通时单线联系,别人无法插手进来,这样可以保证安全。为什么要使用隧道的手段,大家可以去看谍战片。