技术标签: springcloud
微服务条目 | 落地技术 |
---|---|
服务开发 | SpringBoot,Spring,SpringMVC |
服务配置与管理 | Netflix公司的Archaius、阿里的Diamond等 |
服务注册与发现 | Eureka、Consul、Zookeeper等 |
服务调用 | Rest、RPC、gRPC |
服务熔断器 | Hystrix、Envoy等 |
负载均衡 | Ribbon、Nginx等 |
服务接口调用(客户端调用服务的简化工具) | Feign等 |
消息队列 | Kafka、RabbitMQ、ActiveMQ等 |
服务配置中心管理 | SpringCloudConfig、Chef等 |
服务路由(API网关) | Zuul等 |
服务监控 | Zabbix、Nagios、Metrics、Specatator等 |
全链路追踪 | Zipkin、Brave、Dapper等 |
服务部署 | Docker、OpenStack、Kubernetes等 |
数据流操作开发包 | SpringCloud Stream(封装与Redis,Rabbit,Kafka等发送接收消息) |
事件消息总线 | SpringCloud Bus |
功能点/服务框架 | Netflix/SpringCloud | Motan | gRPC | Thrift | Dubbo/DubboX |
---|---|---|---|---|---|
功能定位 | 完整的微服务架构 | RPC框架,但整合了ZK或Consul,实现集群环境的基本服务注册/发现 | RPC框架 | RPC框架 | 服务框架 |
支持Rest | 是,Ribbon支持多种可插拔的序列化选择 | 否 | 否 | 否 | 否 |
支持RPC | 否 | 是 | 是 | 是 | 是 |
支持多语言 | 是(Rest形式) | 否 | 是 | 是 | 否 |
服务注册/发现 | 是(Eureka) Eureka服务注册表,Karyon服务端框架支持服务自注册和健康检查 | 是(zookeeper/consul) | 否 | 否 | 是 |
负载均衡 | 是(服务端zuul+客户端Ribbon) zuul-服务,动态路由 云端负载均衡 Eureka(针对中间层服务器) | 是(客户端) | 否 | 否 | 是(客户端) |
配置服务 | Netflix Archaius SpringCloud Config Server集中配置 | 是(zookeeper提供) | 否 | 否 | 否 |
服务调用链监控 | 是(zuul) Zuul提供边缘服务,API网关 | 否 | 否 | 否 | 否 |
高可用/容错 | 是(服务端Hystrix+客户端Ribbon) | 是(客户端) | 否 | 否 | 是(客户端) |
典型应用案例 | Netflix | Sina | |||
社区活跃度 | 高 | 一般 | 高 | 一般 | 2017年7月才重启 |
学习难度 | 中等 | 一般 | 高 | 一般 | 低 |
文档丰富度 | 高 | 一般 | 一般 | 一般 | 高 |
其他 | Spring Cloud Bus为我们应用程序带来了更多管理端点 | 支持降级 | Netflix内部在开发集成gRPC | IDL定义 | 实践公司比较多 |
SpringBoot:专注于快速方便的开发单个个体微服务(关注微观)
SpringCloud:关注全局的微服务协调治理框架,将SpringBoot开发的一个个单体微服务组合并管理起来(关注宏观)
Dubbo | Spring | |
---|---|---|
服务注册中心 | Zookeeper | Spring Cloud Netfilx Eureka |
服务调用方式 | RPC | REST API |
服务监控 | Dubbo-monitor | Spring Boot Admin |
断路器 | 不完善 | Spring Cloud Netflix Hystrix |
服务网关 | 无 | Spring Cloud Netflix Zuul |
分布式配置 | 无 | Spring Cloud Config |
服务跟踪 | 无 | Spring Cloud Sleuth |
消息总线 | 无 | Spring Cloud Bus |
数据流 | 无 | Spring Cloud Stream |
批量任务 | 无 | Spring Cloud Task |
最大区别:
####总结
概述:SpringCloud工程由一个父工程和若干个Module组成
应该遵循的条件:约定 > 配置 > 编码
RestTemplate是Spring提供的用于访问Rest服务的客户端模板工具集,提供了多种远程访问Http的方法
在一些不涉及实现方法的模块中(消费者),只需要调用其他服务暴露出的接口即可满足的需求,使用RestTemplate类中的方法可以发出需要的HTTP请求并得到返回结果。(类似Ajax)
RestTemplate restTemplate = new RestTemplate();
//url:请求地址
//requestMap:请求参数
//type.class:HTTP响应转换成的对象类型
restTemplate.getForObject(url,type.class);
restTemplate.postForObject(url,requestMap,type.class);
<dependencies>
<dependency>
<groupId>com.lzl</groupId>
<artifactId>microservice-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml
type-aliases-package: com.XXX.entity
mapper-locations:
- classpath:mybatis/mapper/**/*.xml
spring:
application:
name: microservicecloud-dept #为这个服务取名,非常重要!!!!!
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/cloudDB01
username: root
password: 123456
dbcp2:
min-idle: 5 #最小连接数
initial-size: 5 #初始化连接数
max-total: 10 #最大连接数
max-wait-millis: 200 #等待连接最长的超时时间
package com.XXX;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Provider8001_APP {
public static void main(String[] args) {
SpringApplication.run(Provider8001_APP.class,args);
}
}
Eureka就像一个物业管理公司,其他微服务就像小区的住户,每个住户入住时都要向物业管理公司注册,并定时向物业公司交管理费
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,职责是维护实例,不参加检索
service-url:
defaultZone: http://${
eureka.instance.hostname}:${
server.port}/eureka/ #设置eureka server的交互地址,即对外暴露的地址
package com.XXX;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class Eureka7001_APP {
public static void main(String[] args) {
SpringApplication.run(Eureka7001_APP.class,args);
}
}
启动主程序,访问该服务地址即可
在要注册的微服务的pom.xml文件中增加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
server:
port: 17001
spring:
application:
name: eurekaClient # 修改服务名
@SpringBootApplication
@EnableEurekaClient
public class Provider8001_APP {
public static void main(String[] args) {
SpringApplication.run(Provider8001_APP.class,args);
}
}
eureka:
instance:
instance-id: dept8001 #修改别名
prefer-ip-address: true #显示IP地址
在查看Eureka时点击进入某个微服务的info时,能给查看者一些必要的信息,可以帮助查看者快速的了解该微服务,开发中十分有意义。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<build>
<finalName>microservicecloud</finalName>
<resources>
<resource>
<!--允许扫描该路径下的资源文件-->
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<!--指定动态获取以$标志开头结尾的信息-->
<delimit>$</delimit>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
info:
author: XXX
build-version: $project.version$
Eureka的自我保护机制主要是为了网络异常时保持高可用设计的,当在Eureka中注册的微服务超过设定是时间内(默认90秒)没有向Eureka服务端发送心跳,该微服务会进入自我保护模式。在自我保护模式中,Eureka会保护服务注册表中的信息,不会注销任何服务实例,直至收到的心跳数恢复至阈值以上,该微服务退出自我保护模式。
好死不如赖活:Eureka的设计哲学是宁可保留错误的服务信息,也不盲目注销可能健康的服务。所以异常的服务不会被注销,而是进入了自我保护模式。
在Eureka Server模块下的yml文件中添加配置信息即可,true表示打开自我保护模式;false表示关闭自我保护模式(不推荐)
server:
enable-self-preservation: false
系统中的微服务可以通过Eureka的服务发现去获得在Eureka中注册的服务的信息,这是一个对外暴露的接口。
@Autowired
private DiscoveryClient discoveryClient;
@ResponseBody
@GetMapping("/provider/discovery")
public Object discovery(){
List<String> list = discoveryClient.getServices();
System.out.println(list);
List<ServiceInstance> insList = discoveryClient.getInstances("MICROSERVICECLOUD-DEPT");
for (ServiceInstance si:insList) {
System.out.println(si.getHost() +"," + si.getServiceId() +"," +si.getPort() +"," +si.getUri() +"," +si.getMetadata());
}
return this.discoveryClient;
}
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class Provider8001_APP {
public static void main(String[] args) {
SpringApplication.run(Provider8001_APP.class,args);
}
}
在controller方法中使用restTemplate对象调用provider中暴露的URL 并获得返回对象即可
@GetMapping("/discovery")
public Object discovery() {
return restTemplate.getForObject(URL_PREFIX+"/provider/discovery",Object.class);
}
集群就是在不同的机器上配置相同的服务来构建要一个大的运算整体
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #hostname为hosts文件中映射的地址
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,职责是维护实例,不参加检索
service-url:
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置eureka server的交互地址
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #其他两个服务端的地址
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
http://eureka7001.com:7001
http://eureka7002.com:7002
http://eureka7003.com:7003
Eureka遵守AP,Zookeeper遵守CP(C:强一致性,A:高可用,P:分区容错性,三者只能选其二,高并发下P必选)
Zookeeper | Eureka |
---|---|
当网络出现故障时,剩余zk集群会发起投票选举新的leader,但是此过程会持续30~120s,此过程对于高并发来说十分漫长,会导致整个注册服务的瘫痪,这是不可容忍的 | 在15分钟内85%的节点都没有心跳,则注册中心 会认为客户端与之出现了网络故障,则会进入自动保护模式。1.Eureka不会移除没有收到心跳的服务;2.新的服务仍能在服务端注册,但是暂时不会被同步到其他节点上直到网络稳定 |
Eureka可以很好的应对网络故障导致部分节点失去连接的情况,而不会像zookeeper那样导致整个注册服务系统的瘫痪。
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具。Ribbon会自动帮助你基于某种规则(简单轮询、随机连接等),也可以实现自定义的负载均衡算法。
英文名称:Load Balance,微服务或分布式集群中常用的一种应用
简单来说负载均衡就是将用户的请求ping平摊的分配到多个任务上,从而是系统达到HA(高可用)
两种负载均衡:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
register-with-eureka: false #作为消费者不提供服务,不应该注册自己
@SpringBootApplication
@EnableEurekaClient
public class Consumer80_APP {
public static void main(String[] args) {
SpringApplication.run(Consumer80_APP.class,args);
}
}
private static final String URL_PREFIX = "http://MICROSERVICECLOUD-DEPT/";
架构示意图:
目标:构建provider集群后consumer通过负载均衡轮询调用在Eureka中注册的服务
spring:
application:
name: microservicecloud-dept #同一集群下必须使用同一服务名!!!!!
Ribbon其实就是一个软负载均衡的客户端组件,可以和其他需要请求的客户端结合使用。
IRule:根据特定算法从服务列表中选取一个需要访问的服务
IRule是一个接口,七大方法是其自带的落地实现类
只需在配置类中配置一个返回具体方法的bean即可
@Bean
public IRule MyRule(){
return new RandomRule();
}
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "MICROSERVICECLOUD-DEPT",configuration = MyRule.class)
public class Consumer80_APP {
public static void main(String[] args) {
SpringApplication.run(Consumer80_APP.class,args);
}
}
####通过修改源代码获得自定义算法
目标:每个服务调用5次后再进行轮询(调用次数不是很对,懒得改了)
package com.Rules;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.RoundRobinRule;
import com.netflix.loadbalancer.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class MyRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter;
private static final boolean AVAILABLE_ONLY_SERVERS = true;
private static final boolean ALL_SERVERS = false;
private int total = 0;
private int currentIndex = 0;
private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
public MyRule() {
nextServerCyclicCounter = new AtomicInteger(0);
}
public MyRule(ILoadBalancer lb) {
this();
setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
while (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (total > 5) {
total = 0;
int nextServerIndex = incrementAndGetModulo(serverCount);
currentIndex = nextServerIndex;
server = allServers.get(nextServerIndex);
}else {
if (currentIndex>=serverCount) {
currentIndex = 0;
}
server = allServers.get(currentIndex);
total++;
}
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
/**
* Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
*
* @param modulo The modulo to bound the value of the counter.
* @return The next value.
*/
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
Feign是一个声明式WebService客户端,使用方法时定义一个接口并在上面添加注解即可。Feign支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持SpringMVC和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
<dependencies>
<dependency>
<groupId>com.XXX</groupId>
<artifactId>microservice-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService {
@PostMapping("/dept")
public boolean addDept(Dept dept);
@GetMapping("/dept")
public List<Dept> findAll();
@GetMapping("/dept/{id}")
public Dept findById(@PathVariable("id")Integer id);
}
@RestController
@RequestMapping("/consumer")
public class ConsumerDeptController {
@Autowired
private DeptClientService service;
@PostMapping("/dept")
public boolean addDept(Dept dept){
return service.addDept(dept);
}
@GetMapping("/dept")
public List<Dept> findAll(){
return service.findAll();
}
@GetMapping("/dept/{id}")
public Dept findById(@PathVariable("id")Integer id){
return service.findById(id);
}
}
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {
"com.XXX"})
@ComponentScan("com.XXX")
public class Consumer80Feign_APP {
public static void main(String[] args) {
SpringApplication.run(Consumer80Feign_APP.class,args);
}
}
多个微服务互相调用的时候,如果A调用B、C,而B、C又继续调用其他微服务,这就是扇出(像一把扇子一样慢慢打开。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
@ResponseBody
@GetMapping("/dept/{id}")
@HystrixCommand(fallbackMethod = "nullDeptFallBack")
public Dept findById(@PathVariable("id")Integer id) {
Dept dept = deptService.findById(id);
if (null == dept){
throw new RuntimeException("返回值为空!");
}
return dept;
}
public Dept nullDeptFallBack(@PathVariable("id")Integer id) {
System.out.println(111);
return new Dept().setId(id).setDeptName("nullName").setDbSource("nullDB");
}
如果按照上面的熔断案例来做的话,Controller下的每个方法,都要给其编写一个FallBack方法,当方法慢慢变多,就会造成代码膨胀,一个是增加编写的工作量,另外一个也会增大维护的难度,代码的耦合度也会高,是十分不合理的,所以要将其解耦。
因为服务端的是通过实现接口访问服务端的,如果在父接口上实现了FallBack方法,通过这样一种方式去维护起来就能实现解耦,也顺便完成了降级的机制。
import com.XXX.entity.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class DeptClientServiceFallBackFactory implements FallbackFactory<DeptClientService> {
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
public boolean addDept(Dept dept) {
return false;
}
public List<Dept> findAll() {
return null;
}
public Dept findById(Integer id) {
return new Dept().setId(id).setDeptName("服务器跪了,").setDbSource("迟点来吧");
}
};
}
}
@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)
public interface DeptClientService {
@PostMapping("/dept")
public boolean addDept(Dept dept);
@GetMapping("/dept")
public List<Dept> findAll();
@GetMapping("/dept/{id}")
public Dept findById(@PathVariable("id")Integer id);
}
feign:
hystrix:
enabled: true
介绍:SpringCloud对Hystrix Dashboard进行了整合,可以对通过Hystrix发起的请求进行准实时统计,并以报表和图形的形式展示给用户(包括每秒执行多少次请求成功和失败等)。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
@SpringBootApplication
@EnableHystrixDashboard
public class DashBoard9001_APP {
public static void main(String[] args) {
SpringApplication.run(DashBoard9001_APP.class,args);
}
}
代理:Zuul提供外部的请求转发到具体的微服务实例中的服务
路由:Zuul可以对外部访问实现统一的入口
过滤:Zuul可以对外部访问进行干预,如请求校验、服务聚合等
Zuul需要配合Eureka使用,需要在Eureka中注册并获得其他微服务的信息
理解:Zuul就像大楼的保安,可以请他找人(代理),找的人在外面叫什么名字(路由),准不准你进楼(过滤)。因为保安属于物业公司,所以保安要在物业公司注册,所获得的信息也来源于物业公司(与Eureka的关系)。
<!-- 注意这里必须引入 eureka zuul 是有eureka发现服务的,如果这个包,
则会报服务不存在-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
server:
port: 9527
spring:
application:
name: microservicecloud-zuul #为这个服务取名,非常重要!!!!!
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: zuul.com
prefer-ip-address: true
127.0.0.0 zuul.com
@SpringBootApplication
@EnableZuulProxy
public class Zuul9527_APP {
public static void main(String[] args) {
SpringApplication.run(Zuul9527_APP.class,args);
}
}
启动测试,访问规则:步骤3中指定映射+端口号+微服务名称+访问路径。
当不向暴露真实的服务名时,可以对服务名进行映射,只需在application.yml中配置即可,具体作用看注释
zuul:
routes:
#dept0是可以自定义的只是作为区分,没什么具体意义
dept0.serviceId: microservicecloud-dept
#路径也是自定义的,支持通配符
dept0.path: /dept10/**
#需要隐藏的服务名,可以使用通配符,配置之后通过这个微服务名访问就失效了
ignored-services: microservicecloud-*
#设置统一公共前缀,设置后访问路径:http://zuul.com:9527/nihao/dept10/dept/3
prefix: /nihao
注:因为Zuul是针对外部访问管理的,所以配置了隐藏的服务,在系统中其他模块进行服务名访问时依然可以正常运行的,这点可以通过打开consumer模块进行验证!
分布式系统面临的配置问题:微服务意味着将单体应用拆分成一个个自服务,这些服务都是要相应的配置信息才能运行,随着系统内微服务数量越来越多,配置信息也不断地增多,所以一套集中式的、动态的配置管理设施是必不可少的。
![SpringCloud Config架构图](E:\笔记\images\SpringCloud Config架构图.png)
目标:将配置文件部署在github,Config服务端从github获取配置
<!-- springCloud Config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- 避免Config的Git插件报错:org/eclipse/jgit/api/TransportConfigCallback -->
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>4.10.0.201712302008-r</version>
</dependency>
spring:
profiles:
active:
- dev
---
spring:
profiles: dev
application:
name: microservicecloud-config-XXX-dev
---
spring:
profiles: test
application:
name: microservicecloud-config-XXX-test
server:
port: 3344
spring:
application:
#为这个服务取名,非常重要!!!!!
name: microservicecloud-config
cloud:
config:
server:
git:
# uri填github上仓库地址
uri: https://github.com/XXXX/SpringCloud_Configuration.git
@SpringBootApplication
@EnableConfigServer
public class ConfigServer3344_APP {
public static void main(String[] args) {
SpringApplication.run(ConfigServer3344_APP.class,args);
}
}
/{application}/{profile}[/{lable}]
/{application}-{profile}.yml
/{lable}/{application}-{profile}.yml
/{application}-{profile}.properties
/{lable}/{application}-{profile}.properties
可用例子(返回格式可能不大相同,但返回值相同):
不可用例子:
介绍:客户端主要是在加载时通过config server服务端获得github配置仓库的地址,进而通过目标配置文件的文件名获取相应的配置,最后将取得的配置对自身资源进行赋值并提供访问
1.创建远程配置yml文件并上传到github上。如下测试案例因为需要进行测试,所以配置了两个profiles方便切换并观察
spring:
profiles:
active:
- dev
---
server:
port: 8201
spring:
profiles: dev
application:
name: microservicecloud-config-client-dev
eureka:
client:
service-url:
defaultZone: http://eureka-dev.com:7001/eureka/
---
server:
port: 8202
spring:
profiles: test
application:
name: microservicecloud-config-client-test
eureka:
client:
service-url:
defaultZone: http://eureka-dev.com:7001/eureka/
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
spring:
cloud:
config:
name: application_config #需要从github上读取的资源名称,注意没有yml后缀名
profile: test #本次访问的配置项
label: master
uri: http://config3344.com:3344 #本微服务启动后先去找3344号服务,通过SpringCloudConfig获取GitHub的服务地址
spring:
application:
name: microservicecloud_config
修改host文件增加映射,和3344一样
编写主启动类,没什么特别的,最基本的主启动类
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args){
SpringApplication.run(ConfigClientApplication.class,args);
}
}
编写controller,此步骤也比较关键,主要是利用@Value注解赋值,若写错了bootstrap.yml中的配置文件名称而没有获取到配置,启动时这里会抛出异常。@Value中注解的参数即是目标配置文件中的参数值,使用El表达式获取
@org.springframework.web.bind.annotation.RestController
public class RestController {
@Value("${server.port}")
private String port;
@Value("${eureka.client.service-url.defaultZone}")
private String eurekaZone;
@Value("${spring.application.name}")
private String name;
@GetMapping("/config")
@Override
public String toString() {
return "RestController{" +
"port='" + port + '\'' +
", eurekaZone='" + eurekaZone + '\'' +
", name='" + name + '\'' +
'}';
}
}
介绍:其实前面client的配置案例都是帮助理解这个组件为主,并没有很大的实际意义。。。。。。这节的案例中是配置一个Provider,一个eureka,他们的配置统一在github上获取,实现统一配置分布式管理和多环境变更,这个才比较有实战意义。
Eureka配置文件示例:
spring:
profiles:
active:
- dev
---
spring:
profiles: dev
application:
name: microservicecloud-eureka-client-dev
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #hostname为hosts文件中映射的地址
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,职责是维护实例,不参加检索
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ #设置eureka server的交互地址
---
spring:
profiles: test
application:
name: microservicecloud-eureka-client-dev
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #hostname为hosts文件中映射的地址
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,职责是维护实例,不参加检索
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ #设置eureka server的交互地址
Provider配置文件示例:
spring:
profiles:
active:
- dev
---
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml
type-aliases-package: com.XXX.entity
mapper-locations:
- classpath:mybatis/mapper/**/*.xml
spring:
profiles: dev
application:
name: microservicecloud-dept #为这个服务取名,非常重要!!!!!
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://192.168.88.246:3306/cloudDB01
username: root
password: 123456
dbcp2:
min-idle: 5 #最小连接数
initial-size: 5 #初始化连接数
max-total: 10 #最大连接数
max-wait-millis: 200 #等待连接最长的超时时间
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
instance:
instance-id: dept8001
prefer-ip-address: true
---
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml
type-aliases-package: com.XXX.entity
mapper-locations:
- classpath:mybatis/mapper/**/*.xml
spring:
profiles: test
application:
name: microservicecloud-dept #为这个服务取名,非常重要!!!!!
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://192.168.88.246:3306/cloudDB02
username: root
password: 123456
dbcp2:
min-idle: 5 #最小连接数
initial-size: 5 #初始化连接数
max-total: 10 #最大连接数
max-wait-millis: 200 #等待连接最长的超时时间
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
instance:
instance-id: dept8001
prefer-ip-address: true
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
spring:
cloud:
config:
name: application_config #需要从github上读取的资源名称,注意没有yml后缀名
profile: test #本次访问的配置项
label: master
uri: http://config3344.com:3344 #本微服务启动后先去找3344号服务,通过SpringCloudConfig获取GitHub的服务地址
spring:
application:
name: microservicecloud_config
文章浏览阅读1.1w次,点赞7次,收藏34次。vue-grid-layout的使用、实例、遇到的问题和解决方案_vue-grid-layout
文章浏览阅读218次。然后连接一个数据源,就会在下面自动产生一个添加附件的组件。把这个控件复制粘贴到页面里,就可以单独使用来上传了。插入一个“编辑”窗体。_powerapps点击按钮上传附件
文章浏览阅读264次。(1) Abstraction (抽象)(2) Polymorphism (多态)(3) Inheritance (继承)(4) Encapsulation (封装)_"object(cnofd[\"ofdrender\"])十条"
文章浏览阅读133次。删除node_modules,重新npm install看是否成功。在 package.json 文件中的 scripts 中加入。修改你的第三方库的bug等。然后目录会多出一个目录文件。_修改 node_modules
文章浏览阅读883次。【代码】【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure
文章浏览阅读1w次,点赞13次,收藏97次。整理5个优秀的微信小程序开源项目。收集了微信小程序开发过程中会使用到的资料、问题以及第三方组件库。_微信小程序开源模板
文章浏览阅读128次。Centos7最简搭建NFS服务器_centos7 搭建nfs server
文章浏览阅读1.2k次,点赞2次,收藏3次。前言mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。..._mybaitis-plus ruledataobjectattributemapper' and 'com.picc.rule.management.d
文章浏览阅读325次。EECE 1080C / Programming for ECESummer 2022Laboratory 4: Global Functions PracticePlagiarism will not be tolerated:Topics covered:function creation and call statements (emphasis on global functions)Objective:To practice program development b_eece1080c
文章浏览阅读53次。被同机房早就1年前就学过的东西我现在才学,wtcl。设要求的数为\(x\)。设当前处理到第\(k\)个同余式,设\(M = LCM ^ {k - 1} _ {i - 1}\) ,前\(k - 1\)个的通解就是\(x + i * M\)。那么其实第\(k\)个来说,其实就是求一个\(y\)使得\(x + y * M ≡ a_k(mod b_k)\)转化一下就是\(y * M ...
文章浏览阅读1.3k次。首先,问题是如何出现的?晚上复查代码,发现一个activity没有调用自己的ondestroy方法我表示非常的费解,于是我检查了下代码。发现再finish代码之后接了如下代码finish();System.exit(0);//这就是罪魁祸首为什么这样写会出现问题System.exit(0);////看一下函数的原型public static void exit (int code)//Added ..._android 手动杀死app,activity不执行ondestroy
文章浏览阅读894次。Q: SylixOS 版权是什么形式, 是否分为<开发版税>和<运行时版税>.A: SylixOS 是开源并免费的操作系统, 支持 BSD/GPL 协议(GPL 版本暂未确定). 没有任何的运行时版税. 您可以用她来做任何 您喜欢做的项目. 也可以修改 SylixOS 的源代码, 不需要支付任何费用. 当然笔者希望您可以将使用 SylixOS 开发的项目 (不需要开源)或对 SylixOS 源码的修改及时告知笔者.需要指出: SylixOS 本身仅是笔者用来提升自己水平而开发的_select函数 导致堆栈溢出 sylixos