Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十三):配置中心(Config、Bus)
在线演示
演示地址:http://139.196.87.48:9002/kitty
用户名:admin 密码:admin
技术背景
如今微服务架构盛行,在分布式系统中,项目日益庞大,子项目日益增多,每个项目都散落着各种配置文件,且随着服务的增加而不断增多。此时,往往某一个基础服务信息变更,都会导致一系列服务的更新和重启,运维也是苦不堪言,而且还很容易出错。于是,配置中心便由此应运而生了。
目前市面上开源的配置中心有很多,像Spring家族的Spring Cloud Config, Apache的Apache Commons Configuration,淘宝的diamond, 百度的disconf, 360的QConf等等,都是为了解决这类问题。当下Spring体系大行其道,我们当然也优先选择Spring Cloud Config了。
Spring Cloud Config
Spring Cloud Config 是一套为分布式系统中的基础设施和微服务应用提供集中化配置的管理方案,它分为服务端与客户端两个部分。服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息。客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定的配置中心来管理服务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。
Spring Cloud Config对服务端和客户端中的环境变量和属性配置 实现了抽象映射,所以它除了适用于 Spring 应用,也是可以在任何其他语言应用中使用的。Spring Cloud Config 实现的配置中心默认采用 Git 来存储配置信息,所以使用 Spring Cloud Config 构建的配置服务器,天然就支持对微服务应用配置信息的版本管理,并且可以通过 Git 客户端工具非常方便的管理和访问配置内容。当然它也提供了对其他存储方式的支持,比如:SVN 仓库、本地化文件系统等。
实现案例
准备配置文件
首先在GIT下,新建config-repo目录,用来存放配置文件,如下图所示,分别模拟了三个环境的配置文件。
分别编辑三个文件,配置 comsumer.hello 属性的值为 comsumer.hello=hello, this is xx configurations.
服务端实现
新建工程
新建 kitty-conifg 工程,作为配置中心的服务端,负责把GIT仓库的配置文件发布为RESTFul接口。
添加依赖
除了Spring Cloud依赖之外,添加配置中心依赖包。
pom.xml
<!--spring config-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
启动类
启动类添加注解 @EnableConfigServer,开启配置服务支持。
KittyConfigApplication.java
package com.louis.kitty.config; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer; @EnableConfigServer
@EnableDiscoveryClient
@SpringBootApplication
public class KittyConfigApplication { public static void main(String[] args) {
SpringApplication.run(KittyConfigApplication.class, args);
}
}
配置文件
修改配置文件,添加如下内容。如果是私有仓库需要填写用户名密码,如果是公开仓库,可以不配置密码。
application.yml
server:
port: 8020
spring:
application:
name: kitty-config
cloud:
consul:
host: localhost
port: 8500
discovery:
serviceName: ${spring.application.name} # 注册到consul的服务名称
config:
label: master # git仓库分支
server:
git:
uri: https://gitee.com/liuge1988/kitty.git # 配置git仓库的地址
search-paths: config-repo # git仓库地址下的相对地址,可以配置多个,用,分割。
username: username # git仓库的账号
password: password # git仓库的密码
Spring Cloud Config也提供本地存储配置的方式,只需设置属性spring.profiles.active=native
,Config Server会默认从应用的src/main/resource
目录下检索配置文件。另外也可以通过spring.cloud.config.server.native.searchLocations=file:D:/properties/
属性来指定配置文件的位置。虽然Spring Cloud Config提供了这样的功能,但是为了更好的支持内容管理和版本控制,还是比较推荐使用GIT的方式。
测试效果
启动注册中心,配置中心,访问 http://localhost:8020/kitty-consumer/dev,返回结果如下。
{
"name": "kitty-consumer",
"profiles": ["dev"],
"label": null,
"version": "1320259308dfdf438f5963f95cbce9e0a76997b7",
"state": null,
"propertySources": [{
"name": "https://gitee.com/liuge1988/kitty.git/config-repo/kitty-consumer-dev.properties",
"source": {
"consumer.hello": "hello, this is dev configurations. "
}
}]
}
访问 http://localhost:8020/kitty-consumer/pro,返回结果如下。
{
"name": "kitty-consumer",
"profiles": ["pro"],
"label": null,
"version": "1320259308dfdf438f5963f95cbce9e0a76997b7",
"state": null,
"propertySources": [{
"name": "https://gitee.com/liuge1988/kitty.git/config-repo/kitty-consumer-pro.properties",
"source": {
"consumer.hello": "hello, this is pro configurations. "
}
}]
}
上述的返回的信息包含了配置文件的位置、版本、配置文件的名称以及配置文件中的具体内容,说明server端已经成功获取了git仓库的配置信息。
访问:http://localhost:8020/kitty-consumer-dev.properties,返回结果如下。
修改一下dev配置文件内容如下(末尾加了一个 2):
再次访问:http://localhost:8020/kitty-consumer-dev.properties,返回结果如下。
发现读取的是修改后提交的信息,说明服务端会自动读取最新提交的数据。
仓库中的配置文件会被转换成相应的WEB接口,访问可以参照以下的规则:
- /{application}/{profile}[/{label}]
- /{application}-{profile}.yml
- /{label}/{application}-{profile}.yml
- /{application}-{profile}.properties
- /{label}/{application}-{profile}.properties
以kitty-consumer-dev.properties为例子,它的application是kitty-consumer,profile是dev。client会根据填写的参数来选择读取对应的配置。
客户端实现
添加依赖
打开kitty-consumer工程,添加相关依赖。
pom.xml
<!-- spring-cloud-config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
配置文件
添加一个bootstrap.yml配置文件,添加配置中心,并把注册中心的配置移到这里,因为在通过配置中心查找配置时需要通过注册中心的发现服务。
bootstrap.yml
spring:
cloud:
consul:
host: localhost
port: 8500
discovery:
serviceName: ${spring.application.name} # 注册到consul的服务名称
config:
discovery:
enabled: true # 开启服务发现
serviceId: kitty-config # 配置中心服务名称
name: kitty-consumer # 对应{application}部分
profile: dev # 对应{profile}部分
label: master # 对应git的分支,如果配置中心使用的是本地存储,则该参数无用
配置说明:
- spring.cloud.config.uri:配置中心的具体地址
- spring.cloud.config.name:对应{application}部分
- spring.cloud.config.profile:对应{profile}部分
- spring.cloud.config.label:对应git的分支。如果配置中心使用的是本地存储,则该参数无用
- spring.cloud.config.discovery.service-id:指定配置中心的service-id,便于扩展为高可用配置集群。
特别注意:
上面这些与spring cloud相关的属性必须配置在bootstrap.yml中,这样config部分内容才能被正确加载。
因为config的相关配置会先于application.yml,而bootstrap.yml的加载也是先于application.yml文件的。
application.yml
server:
port: 8005
spring:
application:
name: kitty-consumer
boot:
admin:
client:
url: "http://localhost:8000"
zipkin:
base-url: http://localhost:9411/
sleuth:
sampler:
probability: 1 #样本采集量,默认为0.1,为了测试这里修改为1,正式环境一般使用默认值
# 开放健康检查接口
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
#开启熔断器
feign:
hystrix:
enabled: true
控制器
添加一个 SpringConfigController 控制器, 添加注解 @Value("${comsumer.hello}"),声明hello属性从配置文件读取。
SpringConfigController.java
package com.louis.kitty.consumer.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
class SpringConfigController { @Value("${comsumer.hello}")
private String hello; @RequestMapping("/hello")
public String from() {
return this.hello;
}
}
测试效果
启动注册中心、配置中心,访问: http://localhost:8500,确认相关服务启动并注册。
访问 http://localhost:8005/hello,返回结果。
说明客户端已经成功从服务端读取了配置信息。
现在手动修改一下仓库配置文件的内容,移除末尾数字 2,修改完成并提交。
再次访问 http://localhost:80052/hello,效果如下。
我们发现返回结果并没有读取最新提交的内容,这是因为Spring Boot项目只有在启动的时候才会获取配置文件的内容,虽然GIT配置信息被修改了,但是客户端并没有重新去获取,所以导致读取的信息仍然是旧配置。那么该如何去解决这个问题呢?这就是我们下一章要讲的 Spring Cloud Bus。
Refresh机制
我们在上面讲到,Spring Boot程序只在启动的时候加载配置文件信息,这样在GIT仓库配置修改之后,虽然配置中心服务器能够读取最新的提交信息,但是配置中心客户端却不会重新读取,以至于不能及时的读取更新后的配置信息。这个时候就需要一种通知刷新机制来支持了。
refresh机制是Spring Cloud Config提供的一种刷新机制,它允许客户端通过POST方法触发各自的/refresh,只要依赖spring-boot-starter-actuator包就拥有了/refresh的功能,下面我们为我们的客户端加上刷新功能,以支持更新配置的读取。
添加依赖
我们的 kitty-consumer 在之前已经添加过actuator依赖,所以这里就不用添加了,如果之前没有添加需要加上。actuator是健康检查依赖包,依赖包里携带了 /refresh 的功能。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
在使用配置属性的类型加上 @RefreshScope 注解,这样在客户端执行 /refresh 的时候就会刷新此类下面的配置属性了。
package com.louis.kitty.consumer.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RefreshScope
@RestController
class SpringConfigController { @Value("${consumer.hello}")
private String hello; @RequestMapping("/hello")
public String from() {
return this.hello;
}
}
修改配置
健康检查接口开放需要在配置文件添加以下内容,开放refresh的相关接口,因为这个我们在之前也配置过了,所以也不需添加了。
management:
endpoints:
web:
exposure:
include: "*"
通过上面的接口开放配置,以后以post请求的方式访问 http://localhost:8005/actuator/refresh 时,就会更新修改后的配置文件了。
特别注意:
这里存在着版本大坑,1.x跟2.x的配置不太一样,我们用的是2.0+版本,务必注意。
1.安全配置变更
新版本
management.endpoints.web.exposure.include="*"
老版本
management.security.enabled=false
2.访问地址变更
新版本
http://localhost:8005/actuator/refresh
老版本
http://localhost:8005/refresh
这里还是解释一下上面这个配置起到了什么具体作用,其实actuator是一个健康检查包,它提供了一些健康检查数据接口,refresh功能也是其中的一个接口,但是为了安全起见,它默认只开放了health和info接口(启动信息会包含如下图所示信息),而上面的配置就是设置要开放哪些接口, 我们设置成 “*”,是开放所有接口。你也可以指定开发几个,比如: health,info,refresh,而这里因为我们需要用的refresh功能,所以需要把refresh接口开放出来。
设置成 “*” 后,启动信息会包含以下信息,而这个叫refresh的post方法,就是我们需要的,上面说的接口地址变更从这里也可以看得出来。
测试效果
重新启动服务,访问 http://localhost:8005/hello,返回结果如下。
修改仓库配置内容,末尾加个数字 5,如下图所示。
再次访问 http://localhost:8005/hello,如我们所料,结果并没有更新,因为我们还没有调refresh方法。
通过工具或自写代码发送post请求 http://localhost:8005/actuator/refresh,刷新配置。
这里通过在线测试网站发送,地址:https://getman.cn/Mo2FX 。
注意:先让你的Chrome支持跨域。设置方法:在快捷方式的target后加上 --disable-web-security --user-data-dir,重启即可。
刷新之后,再次访问 http://localhost:8005/hello,返回结果如下。
查看返回结果,刷新之后已经可以获取最新提交的配置内容,但是每次都需要手动刷新客户端还是很麻烦,如果客户端数量一多就简直难以忍受了,有没有什么比较好的办法来解决这个问题呢,那是当然的,答案就是:Spring Cloud Bus。
Spring Cloud Bus
Spring Cloud Bus,被大家称为消息总线,它通过轻量级的消息代理来连接各个分布的节点,可以利用像消息队列的广播机制在分布式系统中进行消息传播,通过消息总线可以实现很多业务功能,其中对于配置中心客户端刷新,就是一个非常典型的使用场景。
下面这张图可以很好的解释消息总线的作用流程(图片描述来源:纯洁的微笑:配置中心博文)。
Spring Cloud Bus 进行配置更新步骤如下:
1、提交代码触发post请求给/actuator/bus-refresh
2、server端接收到请求并发送给Spring Cloud Bus
3、Spring Cloud bus接到消息并通知给其它客户端
4、其它客户端接收到通知,请求Server端获取最新配置
5、全部客户端均获取到最新的配置
安装RabbitMQ
因为我们需要用到消息队列,我们这里选择RabbitMQ,使用Docker进行安装。
拉取镜像
执行以下命令,拉取镜像。
docker pull rabbitmq:management
完成之后执行以下命令查看下载镜像。
docker images
创建容器
执行以下命令,创建docker容器。
docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management
启动成功之后,可以执行以下命令查看启动容器。
docker ps
登录界面
容器启动之后就可以访问web管理界面了,访问 http://宿主机IP:15672。
系统提供了默认账号。 用户名:guest 密码: guest
管理界面
客户端实现
添加依赖
打开客户端 kitty-consumer,添加消息总线相关依赖。
pom.xml
<!-- bus-amqp -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
修改配置
修改配置,添加RebbitMq的相关配置,这样客户端代码就改造完成了。
bootstrap.yml
spring:
cloud:
consul:
host: localhost
port: 8500
discovery:
serviceName: ${spring.application.name} # 注册到consul的服务名称
config:
discovery:
enabled: true # 开启服务发现
serviceId: kitty-config # 配置中心服务名称
name: kitty-consumer # 对应{application}部分
profile: dev # 对应{profile}部分
label: master # 对应git的分支,如果配置中心使用的是本地存储,则该参数无用
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
服务端实现
添加依赖
修改 kitty-conifg,添加相关依赖。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
修改配置,添加RabbitMq的和接口开放相关配置,这样服务端代码也改造完成了。
application.yml
server:
port:
spring:
application:
name: kitty-config
cloud:
consul:
host: localhost
port:
discovery:
serviceName: ${spring.application.name} # 注册到consul的服务名称
config:
label: master # git仓库分支
server:
git:
uri: https://gitee.com/liuge1988/kitty.git # 配置git仓库的地址
search-paths: config-repo # git仓库地址下的相对地址,可以配置多个,用,分割。
username: username # git仓库的账号
password: password # git仓库的密码
rabbitmq:
host: localhost
port:
username: guest
password: guest
management:
endpoints:
web:
exposure:
include: "*"
测试效果
1.启动服务端,成功集成消息总线后,启动信息中可以看到如下图中的信息。
2.启动客户端,发现居然报错了,网上也找不到相关资料,也没见其他人提过相关问题。猜测是网上教程多是使用Euraka,而这里用的时Consul,瞎鼓捣了好久,反正是不想换回Euraka,2.0停止开发消息出来以后,将来还不定什么情况,只能硬着头皮解决了。
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'configServerRetryInterceptor' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:685) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1210) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.getDelegate(AnnotationAwareRetryOperationsInterceptor.java:180) ~[spring-retry-1.2.2.RELEASE.jar:na]
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:151) ~[spring-retry-1.2.2.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.cloud.config.client.ConfigServerInstanceProvider$$EnhancerBySpringCGLIB$$dd44720b.getConfigServerInstances(<generated>) ~[spring-cloud-config-client-2.0.0.RELEASE.jar:2.0.0.RELEASE]
at org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration.refresh(DiscoveryClientConfigServiceBootstrapConfiguration.java:84) [spring-cloud-config-client-2.0.0.RELEASE.jar:2.0.0.RELEASE]
at org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration.startup(DiscoveryClientConfigServiceBootstrapConfiguration.java:69) [spring-cloud-config-client-2.0.0.RELEASE.jar:2.0.0.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
然后就跟踪代码,发现是在下图中的位置找不到相应的Bean,那么答案就比较明显了,要么是程序有BUG,不过可能性不大,那应该是就是缺包了,在缺失的包里有这个Bean。但是这个Bean是在哪个包?排查了半天也没找到,网上也没有想过资料,对比了一下网上消息总线的配置,依赖也没有少加什么。
没有办法,最后只能自己上手了,不就是在刷新的时候缺少一个拦截器吗,自己给他弄一个试试呗。
使用就加了一个配置类,并在resources下新建了META-INF目录和一个spring。factories文件。
RetryConfiguration.java
package com.louis.kitty.consumer; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
import org.springframework.retry.interceptor.RetryOperationsInterceptor; public class RetryConfiguration {
@Bean
@ConditionalOnMissingBean(name = "configServerRetryInterceptor")
public RetryOperationsInterceptor configServerRetryInterceptor() {
return RetryInterceptorBuilder.stateless().backOffOptions(1000, 1.2, 5000).maxAttempts(10).build();
}
}
spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=com.louis.kitty.consumer.RetryConfiguration
在这里指定新建的拦截器,这样系统初始化时会加载这个Bean。
然后重启启动,果然没有报错了,还是先别高兴,看看能不能用先。
4.先访问一下 http://localhost:8005/hello,效果如下图所示。
5.修改仓库配置文件,把数字5改成15,修改完成提交。
再次访问发现还是旧信息。
6.再用工具发送post请求 http://localhost:8020/actuator/bus-refresh 。
注意这次是向注册中心服务端发送请求,发送成功之后服务端会通过消息总线通知所有的客户端进行刷新。
另外开启消息总线后的请求地址是 /actuator/bus-refresh,不再是refresh了。
7.给服务端发送刷新请求之后,再次访问 http://localhost:8005/hello,结果如下(需要一点刷新时间)。
我们愉快的发现客户端已经能够通过消息总线获取最新配置了。
源码下载
后端:https://gitee.com/liuge1988/kitty
前端:https://gitee.com/liuge1988/kitty-ui.git
作者:朝雨忆轻尘
出处:https://www.cnblogs.com/xifengxiaoma/
版权所有,欢迎转载,转载请注明原文作者及出处。
Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十三):配置中心(Config、Bus)的更多相关文章
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十三):系统备份还原
系统备份还原 在很多时候,我们需要系统数据进行备份还原.我们这里就使用MySql的备份还原命令实现系统备份还原的功能. 新建工程 新建一个maven项目,并添加相关依赖,可以用Spring boot脚 ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十五):Spring Security 版本
在线演示 演示地址:http://139.196.87.48:9002/kitty 用户名:admin 密码:admin 技术背景 到目前为止,我们使用的权限认证框架是 Shiro,虽然 Shiro ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十一):服务网关(Zuul)
在线演示 演示地址:http://139.196.87.48:9002/kitty 用户名:admin 密码:admin 技术背景 前面我们通过Ribbon或Feign实现了微服务之间的调用和负载均衡 ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(一):Kitty 系统介绍
在线演示 演示地址:http://139.196.87.48:9002/kitty 用户名:admin 密码:admin 温馨提示: 有在演示环境删除数据的童鞋们,如果可以的话,麻烦动动小指,右键头像 ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十):服务熔断(Hystrix、Turbine)
在线演示 演示地址:http://139.196.87.48:9002/kitty 用户名:admin 密码:admin 雪崩效应 在微服务架构中,由于服务众多,通常会涉及多个服务层级的调用,而一旦基 ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十九):服务消费(Ribbon、Feign)
技术背景 上一篇教程中,我们利用Consul注册中心,实现了服务的注册和发现功能,这一篇我们来聊聊服务的调用.单体应用中,代码可以直接依赖,在代码中直接调用即可,但在微服务架构是分布式架构,服务都运行 ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十八):注册中心(Spring Cloud Consul)
什么是 Consul Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其它分布式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与 ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十六):容器部署项目
容器部署项目 这一章我们引入docker,采用docker容器的方式部署我们的项目. 首先需要有一个linux环境,并且安装 java 和 maven 以及 docker 环境,这个教程多如牛毛,不再 ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十五):系统服务监控
系统服务监控 新建监控工程 新建Spring Boot项目,取名 kitty-monitor,结构如下. 添加项目依赖 添加 spring boot admin 的相关依赖. pom.xml < ...
随机推荐
- ipv6 docker
DOCKER, IPV6 BASIC CONFIGURATION OF DOCKER ENGINE WITH IPV6 SEPTEMBER 21, 2015 EYEPV6(AT)GMAIL(DOT)C ...
- 关于requests库中文编码问题
转自:代码分析Python requests库中文编码问题 Python reqeusts在作为代理爬虫节点抓取不同字符集网站时遇到的一些问题总结. 简单说就是中文乱码的问题. 如果单纯的抓取微博 ...
- AutoCAD开发3--修改文字图层,颜色
Dim pText As AcadText Dim pColor1 As AcadAcCmColor Set pColor1 = Application.GetInterfaceObject(&quo ...
- 主机性能监控之wmi 获取系统信息及内存性能信息
标 题: 主机性能监控之wmi 获取系统信息及内存性能信息作 者: itdef链 接: http://www.cnblogs.com/itdef/p/3990240.html 欢迎转帖 请保持文本完整 ...
- Alpha项目冲刺
一.团队成员 学号 姓名 211606361 何承华(队长) 211606356 陈宇 211606360 丁培辉 211606333 温志铭 211606343 杨宇潇 211606391 张主强 ...
- 小白的CTF学习之路2——二进制数据基础与运算(上)
今天的第二更,被我拖到了傍晚,嘿嘿,二进制这方面让本就数学不好的我很头疼,所以研究了一段时间 在学习之前我们先了解几个问题: 32位是几个字节? 01011100对于十进制是多少? 00001111向 ...
- C++ MFC棋牌类小游戏day4
根据昨天的计划,今天开始做下面的内容. 1.鼠标点击事件 2.点击坐标进行处理.(坐标转换) 3.判断选中的位置是否有效. 4.确定选中的棋子,设置棋子的状态和棋子所在坐标的状态. 5.判断移动是否有 ...
- PowerShell 使用.NetFramework
我们都知道,由于PowerShell是基于.NETFramework建立的所以它能够具备访问.NET的能力,因为.NET提供了庞大的数据类库,所以我们可以很好的使用PowerShell去完成一些Pow ...
- SWPU-ACM集训队周赛之组队赛(3-11) C题题解
点这里去看题 模拟,注意细节 #include<stdio.h> #include<string.h> int main() { ]; //q[]储存正负信息 scanf(&q ...
- 第二十五节:Java语言基础-面向对象基础
面向对象 面向过程的代表主要是C语言,面向对象是相对面向过程而言,Java是面向对象的编程语言,面向过程是通过函数体现,面向过程主要是功能行为. 而对于面向对象而言,将功能封装到对象,所以面向对象是基 ...