前言:
谢谢大佬文章:https://www.kuangstudy.com/bbs/1374942542566551554
SpringCloud Netflix 中文文档:https://springcloud.cc/spring-cloud-netflix.html
SpringCloud 中文API文档(官方文档翻译版):https://springcloud.cc/spring-cloud-dalston.html
SpringCloud中国社区:http://springcloud.cn/
SpringCloud中文网:https://springcloud.cc
springcloud相比dubbo的技术对比:
一、项目目录及父依赖:
首先在父依赖pom中导好要导入的包,将后续各个子模块公用的jar包等统一提取出来,类似一个抽象父类,具体代码见前言。
二、项目的消费者、服务提供者 api
首先是api (就是一个服务对应的实体类pojo)
package com.chao.springcloud.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@NoArgsConstructor //提供无参的构造方法
@Accessors(chain = true) //链式写法
//所有的实体类必须实现序列化接口
public class Dept implements Serializable {
private Long deptno;
private String dname;
private String db_source;//这个数据是存在哪个数据库的字段
//微服务架构:一个服务对应一个数据库,也就是说同一个信息会存到不同的数据库,因此需要 db_source 进行区分
/**
* 链式写法:
* Dept dept=new Dept();
* dept.setDeptNo(11).setDname('ssss').setDb_source('001')
*/
}
下一个介绍8001端口的服务提供者(8002和8003也一样)
跟普通的springboot项目没区别 不细说了 看源码
下面来介绍消费者 80端口
首先看一下配置文件
其中eureka有三个注册中心的集群
server:
port: 80
eureka:
client:
register-with-eureka: false #不向 eureka 注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
接下来是控制层(使用了restTemplate)(这里是调用服务提供者给的接口)
package com.chao.springcloud.controller;
import com.chao.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
// 消费者不应该有 Service 层,那怎么拿到 Service ?
// RestTemplate:提供多种便捷访问远程 http 服务的方法,简单的 restful 服务模板
// 注册到 spring 中
// RestTemplace 参数:(String url, Class<T> responseType, Object... uriVariables)
@Autowired
private RestTemplate restTemplate;
//通过 Ribbon 实现的时候,地址应该是变量,请求这个应用的名字即可
//private static final String REST_URL_PREFIX="http://localhost:8001";
private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";
@GetMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable Long id){
return restTemplate.getForObject(REST_URL_PREFIX +"/dept/get/"+id, Dept.class);
}
@PostMapping("/consumer/dept/add")
public boolean add(Dept dept ){
return restTemplate.postForObject(REST_URL_PREFIX +"dept/add",dept,Boolean.class);
}
@GetMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX +"/dept/list", List.class);
}
}
PS:这里原来是8001接口 因为当服务提供者只有8001接口一个,但是当访问压力过大,比如需要3个服务提供者(3个数据库)进项负载均衡,也就是他们的名字都是SPRINGCLOUD-PROVIDER-DEPT (可见源码的三个服务提供者的配置)
三、Eureka注册中心
这里是3个注册中心构建的集群 (这里就介绍7001 其他两个都一样)
1、首先编写配置文件
server:
port: 7001
#Eureka
eureka:
instance:
hostname: eureka7001.com # 服务端的实例名称
client:
register-with-eureka: false #表示是否向 Eureka 注册中心注册自己,服务器不用注册
fetch-registry: false # false 表示自己是注册中心
service-url:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
2、然后开启注解即可
四、Ribbon实现负载均衡
此处负载均衡实现代码位于80 消费者处
这里是自定义的负载均衡算法
这里是bean注入,注意这里要实现负载均衡一定要加这个注解
然后启动类一定要标注好即可。
五、Feign实现负载均衡
区别在于 他在api模块加了一个service类
然后在消费方不是RestTemplate 还是大家熟悉的接口写法调用
然后启动类添加注解即可
六、Hystrix:服务熔断
修改controller
/**
* @Auther: csp1999
* @Date: 2020/05/17/22:06
* @Description: 提供Restful服务
*/
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
/**
* 根据id查询部门信息
* 如果根据id查询出现异常,则走hystrixGet这段备选代码
* @param id
* @return
*/
@HystrixCommand(fallbackMethod = "hystrixGet")
@RequestMapping("/dept/get/{id}")//根据id查询
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if (dept==null){
throw new RuntimeException("这个id=>"+id+",不存在该用户,或信息无法找到~");
}
return dept;
}
/**
* 根据id查询备选方案(熔断)
* @param id
* @return
*/
public Dept hystrixGet(@PathVariable("id") Long id){
return new Dept().setDeptno(id)
.setDname("这个id=>"+id+",没有对应的信息,null---@Hystrix~")
.setDb_source("在MySQL中没有这个数据库");
}
}
为主启动类添加对熔断的支持注解@EnableCircuitBreaker
/**
* @Auther: csp1999
* @Date: 2020/05/17/22:09
* @Description: 启动类
*/
@SpringBootApplication
@EnableEurekaClient // EnableEurekaClient 客户端的启动类,在服务启动后自动向注册中心注册服务
@EnableDiscoveryClient // 服务发现~
@EnableCircuitBreaker // 添加对熔断的支持注解
public class HystrixDeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDeptProvider_8001.class,args);
}
}
服务降级
/**
* @Auther: csp1999
* @Date: 2020/05/20/9:18
* @Description: Hystrix服务降级 ~
*/
@Component
public class DeptClientServiceFallBackFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable cause) {
return new DeptClientService() {
@Override
public Dept queryById(Long id) {
return new Dept()
.setDeptno(id)
.setDname("id=>" + id + "没有对应的信息,客户端提供了降级的信息,这个服务现在已经被关闭")
.setDb_source("没有数据~");
}
@Override
public List<Dept> queryAll() {
return null;
}
@Override
public Boolean addDept(Dept dept) {
return false;
}
};
}
}
在DeptClientService中指定降级配置 DeptClientServiceFallBackFactory
@Component //注册到spring容器中
//@FeignClient:微服务客户端注解,value:指定微服务的名字,这样就可以使Feign客户端直接找到对应的微服务
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)//fallbackFactory指定降级配置类
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@GetMapping("/dept/add")
public Boolean addDept(Dept dept);
}
在springcloud-consumer-dept-feign模块中开启降级:
server:
port: 80
# Eureka配置
eureka:
client:
register-with-eureka: false # 不向 Eureka注册自己
service-url: # 从三个注册中心中随机取一个去访问
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
# 开启降级feign.hystrix
feign:
hystrix:
enabled: true
七、Zull路由网关
首先配置文件加入zull的配置
server:
port: 9527
spring:
application:
name: springcloud-zuul #微服务名称
# eureka 注册中心配置
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance: #实例的id
instance-id: zuul9527.com
prefer-ip-address: true # 显示ip
info:
app.name: haust.springcloud # 项目名称
company.name: 河南科技大学西苑校区 # 公司名称
# zull 路由网关配置
zuul:
# 路由相关配置
# 原来访问路由 eg:http://www.cspStudy.com:9527/springcloud-provider-dept/dept/get/1
# zull路由配置后访问路由 eg:http://www.cspstudy.com:9527/haust/mydept/dept/get/1
routes:
mydept.serviceId: springcloud-provider-dept # eureka注册中心的服务提供方路由名称
mydept.path: /mydept/** # 将eureka注册中心的服务提供方路由名称 改为自定义路由名称
# 不能再使用这个路径访问了,*: 忽略,隐藏全部的服务名称~
ignored-services: "*"
# 设置公共的前缀
prefix: /haust
主启动类开启即可
/**
* @Auther: csp1999
* @Date: 2020/05/20/20:53
* @Description: Zull路由网关主启动类
*/
@SpringBootApplication
@EnableZuulProxy // 开启Zuul
public class ZuulApplication_9527 {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication_9527.class,args);
}
}
结尾还有一个config没弄 来日补上