SpringCloud学习总结
SpringCloud学习总结
微服务架构方案
- SpringCloud NetFlix 一站式解决方案
- Apache Dubbo + Zookeeper(注册中心) 半自动,
- SpringCloud Alibaba 一站式解决方案
SpringCloud NetFlix
总体构建
创建maven总项目,导入依赖,不建议使用springCloud2020.0.*及以后版本,2020.0.*版本做了很大改动Springboot依赖根据官网文档推荐选择
pom文件配置总依赖
<dependencyManagement> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR9</version> <type>pom</type> <scope>import</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.5.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencyManagement>版本控制
<eureka.version>2.2.6.RELEASE</eureka.version> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>${eureka.version}</version> </dependency>
注册中心 Eureka
CAP原则
C - consistency 强一致性
A - availability 可用性
P - partition tolerance 分区容错性Eureka遵循AP原则
Zookeeper遵循CP原则
配置Eureka服务端
在工程下新建maven Module作为Eureka服务端
在新建项目下添加pom依赖(注意这里是Eureka服务端所以pom依赖是*-server)
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependencies>application.yml配置
server: port: 7003 #Eureka配置 eureka: instance: hostname: eureka7003.com #eureka服务端的实例名称 client: register-with-eureka: false #表示是否向eureka注册中心注册自己 fetch-registry: false #如果为false则表示自己为注册中心 service-url: #监控页面 defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/新建启动类
package com.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer //服务端启动类 可以接受别人注册进来 public class EurekaServer_7001 { public static void main(String[] args) { SpringApplication.run(EurekaServer_7001.class,args); } }
配置消费者
新建maven Moudle作为生产者,在pom文件中添加依赖
<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-web</artifactId> </dependency>在父工程pom文件添加版本依赖
<properties> <eureka.version>2.2.6.RELEASE</eureka.version> </properties> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>${eureka.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>${eureka.version}</version> </dependency>application.yml配置
server: port: 80 spring: application: name: service-ribbon # register-with-eureka: false #消费者不用注册自己 #Eureka配置 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ registry-fetch-interval-seconds: 10 instance: instance-id: springcloud-consumer-dept80 #修改Eureka默认描述信息
消费者controller
package com.springcloud.controller;
import com.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
@Autowired
DiscoveryClient discoveryClient;
@Bean //注册一个Bean RestTemplate...供我们调用 需要注册到spring中
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@Autowired
private RestTemplate restTemplate;
//通过Ribbon 这里应该是一个变量,通过服务名来访问
private static final String REST_URL_PREFIX = "http://localhost:8001";
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Integer id) {
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
}
@RequestMapping("/consumer/dept/add")
public Boolean add(@RequestBody Dept dept) {
System.out.println(dept);
return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
}
@RequestMapping("consumer/dept/list")
public List<Dept> list() {
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
}
}
配置生产者
新建maven Moudle作为生产者,在pom文件中添加依赖
<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-web</artifactId> </dependency>application.yml配置
server: port: 8003 #mybatis配置 mybatis: type-aliases-package: com.springcloud.pojo mapper-locations: classpath:mapper/*.xml #spring配置 spring: application: name: springcloud-provider-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db03?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC username: root password: tiger #Eureka服务注册地址 eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7002.com:7002/eureka/ register-with-eureka: true fetch-registry: true instance: prefer-ip-address: true instance-id: springcloud-provider-dept8003 #修改Eureka默认描述信息 #info配置 info: app.name: 8888 company.name: 8888在启动类添加 @EnableEurekaClient 开启Eureka服务
负载均衡 ribbon
问题
有些教程在这里要导入ribbon包不过 ,在Netflix-eureka-client2.2.6.RELEASE版本已经集成了ribbon所以不用导入
SpringCloud2020.0.0开始删除了ribbon,还不清楚如何应用,所以建议使用2020.0.0之前的版本,不过,Netflix-eureka-client3.0.0可以
直接配合SpringCloud2020.0.0使用,并且依然支持轮询负载均衡,只是不清楚如何再自定义。如果强行导入其他版本ribbon,会出现找不到
服务的情况 :No instance.....。或者ServerPropertiesAutoConfiguration.class找不到
配置ribbon
ribbon是配置在客户端,也就是消费者端youyu
因为创建消费者时的是eureka-client 而这个包已经包含了ribbon,所以此时不用导入依赖

默认轮询
在注册的给刚刚的Bean添加一个注解
@Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); }
更改均衡配置
再添加一个Bean ribbon默认有几个配置方案,下面这个是随机
@Bean public IRule myRule(){ return new RandomRule(); }
自定义均衡配置
- 在启动类添加注解@RibbonClient(name = "服务名",configuration = 自定义的配置类.class)
- 创建配置类,添加@Configuration 注解,规则可以自己定制
- 注意自己定制的配置不可放到项目启动类同级
服务熔断与降级 Hystrix
服务熔断
服务端,某个服务超时或异常,引起熔断,保险丝功能
配置服务熔断
生产者添加pom依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>启动类添加注解 @EnableCircuitBreaker //添加断路器
controller 给原方法添加备选方案
@GetMapping("/dept/get/{id}") @HystrixCommand(fallbackMethod = "hystrixGet") public Dept get(@PathVariable("id") int id) { Dept dept = service.queryById(id); if (dept == null) { throw new RuntimeException("id=>" + id + ",不存在该用户,或信息无法查到"); } return dept; } //备选方法 public Dept hystrixGet(@PathVariable("id") int id) { return new Dept() .setDeptno(id) .setDname("id=>" + id + ",不存在该用户,或信息无法查到") .setDb_source("没有该数据库"); }
服务降级
客户端,从整体网站请求负载考虑,当某个服务熔断或者关闭之后,服务将不再被调用,此时,在客户端,我们准备一个 FallbackFactory返回一个默认的值,整体服务水平下降。
服务降级实现方式
- 通过Feign
- Zuul网关方式
网关路由 Zuul
- 创建一个新的maven Module 作为网关服务
- 添加pom依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
application.yml
server: port: 9527 spring: application: name: springcloud-zuul eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7002.com:7002/eureka/ instance: instance-id: zuul9527.com prefer-ip-address: true info: app.name: mao-springcloud company.name: blog.mao.com zuul: routes: mydept.serviceId: springcloud-provider-dept mydept.path: /mydept/** #可以用这个路径访问 ignored-services: "*" #不能使用这个路径访问 prefix: /mao #路由前缀编写启动类 添加@EnableZuulProxy 注解
接口编程 Feign
面向接口编程
添加服务接口 也就是对应生产者的controller,再创建实体类
package com.springcloud.service; import com.springcloud.pojo.Dept; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import java.util.List; @Component public interface DeptClientService { @GetMapping("/dept/list") List<Dept> queryAll(); @RequestMapping("/dept/get/{id}") Dept get(@PathVariable("id") Integer id); @RequestMapping("/dept/add") Boolean add(@RequestBody Dept dept); }修改controller 不再使用RestFul
package com.springcloud.controller; import com.springcloud.pojo.Dept; import com.springcloud.service.DeptClientService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class DeptConsumerController { @Autowired private DeptClientService service; @RequestMapping("/consumer/dept/get/{id}") public Dept get(@PathVariable("id") Integer id){ return service.get(id); } @RequestMapping("/consumer/dept/add") public Boolean add(@RequestBody Dept dept){ return null; } @RequestMapping("consumer/dept/list") public List<Dept> list(){ return this.service.queryAll(); } }
服务降级配置
在服务接口类添加注解 @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
可以删除实现类,正常情况下即使在有@Component注解的情况下也不能将接口类注入到Bean,前面建实体类就是为了实现自动注入 但是@FeignClient可以将接口注入到Bean
创建FallbackFactory实现类
package com.springcloud.service; import com.springcloud.pojo.Dept; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; import java.util.List; //降级 @Component public class DeptClientServiceFallbackFactory implements FallbackFactory { @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public List<Dept> queryAll() { List<Dept> deptList = new ArrayList<>(); Dept dept = new Dept().setDeptno(0).setDname("没有找到(服务降级返回)"); deptList.add(dept); return deptList; } @Override public Dept get(Integer id) { return new Dept().setDeptno(id).setDname("没有找到(服务降级返回),这个服务已经被关闭"); } @Override public Boolean add(Dept dept) { return null; } }; } }

浙公网安备 33010602011771号