概述
优缺点
传统网站
springcloud和dubbo区别
实操
第一个springcloud项目,实现多模块的生产消费场景
三个模块,api,consumer,provider
新建maven项目
外部pom文件,注意对应springcloud和springboot版本
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.suda</groupId>
<artifactId>springcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>springcloud-api</module>
<module>springcould-provider</module>
<module>springcloud-consumer</module>
<module>springcloud-eureka</module>
</modules>
<!--打包方式pom-->
<packaging>pom</packaging>
<properties>
<junit.version>4.12</junit.version>
<lombok.version>1.16.10</lombok.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!--springcloud dependence-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring boot dependence-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--database-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
<!--sprintboot starter-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!--log and test-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.3.0-alpha5</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
api
仅包含一个实体类
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.suda</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.suda</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--dependence used in this project,if configed in parent pom, don't need to align the version-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
Department.class
package com.suda.springcloud.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true) //链式写法
public class Department implements Serializable {
private Long departmentId;
private String departmentName;
private String dbSource;
//这个数据存在哪个数据库,微服务中,一个服务对应一个数据库,同一个信息可能在不同数据库
public Department(String departmentName){
this.departmentName=departmentName;
}
}
provider
提供所有服务
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.suda</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>som.suda</groupId>
<artifactId>springcould-provider</artifactId>
<dependencies>
<!--load the api module just write-->
<dependency>
<groupId>com.suda</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!--hot deploy-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!--<version></version>-->
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 8001
mybatis:
type-aliases-package: com.suda.springcloud.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
# configuration:
# map-underscore-to-camel-case: true
spring:
application:
name: springcloud-provider
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&useSSL=true&useLegacyDatetimeCode=false&serverTimezone=America/New_York
username: spark
password: 123456
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<!--驼峰命名和数据库字段不匹配解决方案-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
dao/IDepartmentDao
package com.suda.springcloud.controller;
import com.suda.springcloud.pojo.Department;
import com.suda.springcloud.service.IDepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class DepartmentController {
@Autowired
private IDepartmentService departmentService;
@PostMapping("/department/add")
public boolean addDepartment(Department department){
return departmentService.addDepartment(department);
}
@GetMapping("/department/get/{id}")
public Department addDepartmentById(@PathVariable("id") Long id){
return departmentService.queryById(id);
}
@GetMapping("/department/list")
public List<Department> queryDepartmentById ( ){
return departmentService.queryAll();
}
}
mapper/departmentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.suda.springcloud.dao.IDepartmentDao">
<insert id="addDepartment" parameterType="Department">
insert into department(department_name, db_source) values (#{departmentName}, DATABASE())
</insert>
<select id="queryById" resultType="Department" parameterType="Long">
select * from department where department_id = #{departmentId}
</select>
<select id="queryAll" resultType="Department">
select * from db01.department
</select>
</mapper>
service/IDepartmentService
package com.suda.springcloud.service;
import com.suda.springcloud.pojo.Department;
import java.util.List;
public interface IDepartmentService {
public boolean addDepartment(Department department);
public Department queryById(Long id);
public List<Department> queryAll();
}
service/DepartmentServiceImpl
package com.suda.springcloud.service;
import com.suda.springcloud.dao.IDepartmentDao;
import com.suda.springcloud.pojo.Department;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DepartmentServiceImpl implements IDepartmentService{
@Autowired
private IDepartmentDao departmentDao;
public boolean addDepartment(Department department) {
return departmentDao.addDepartment(department);
}
public Department queryById(Long id) {
return departmentDao.queryById(id);
}
public List<Department> queryAll() {
return departmentDao.queryAll();
}
}
controller/DepartmentController
package com.suda.springcloud.controller;
import com.suda.springcloud.pojo.Department;
import com.suda.springcloud.service.IDepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class DepartmentController {
@Autowired
private IDepartmentService departmentService;
@PostMapping("/department/add")
public boolean addDepartment(Department department){
return departmentService.addDepartment(department);
}
@GetMapping("/department/get/{id}")
public Department addDepartmentById(@PathVariable("id") Long id){
return departmentService.queryById(id);
}
@GetMapping("/department/list")
public List<Department> queryDepartmentById ( ){
return departmentService.queryAll();
}
}
consumer
负责请求provider
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.suda</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.suda</groupId>
<artifactId>springcloud-consumer</artifactId>
<dependencies>
<dependency>
<groupId>com.suda</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
config/ConfigBean
package com.suda.springcloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
//注册 RestTemplate
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
conftoller/DepartmentConsumerController
package com.suda.springcloud.controller;
import com.suda.springcloud.pojo.Department;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DepartmentConsumerController {
//RestTemplate ... register it in spring,
//使用restful风格,从消费端访问生产端,获取数据。
@Autowired
private RestTemplate restTemplate;
private static final String rest_url_prefix = "http://localhost:8001";
@RequestMapping("/consumer/department/get/{id}")
public Department get(@PathVariable("id")Long id){
return restTemplate.getForObject(rest_url_prefix+"/department/get/"+id, Department.class);
}
@RequestMapping("/consumer/department/add")
public boolean add(Department department){
return restTemplate.postForObject(rest_url_prefix+"/department/add",department, Boolean.class);
}
@RequestMapping("/consumer/department/getall")
public List<Department> getList(){
return restTemplate.getForObject(rest_url_prefix+"/department/list",List.class);
}
}
application.yml
server:
port: 80
至此可以实现访问consumer来获得provider的服务,精髓在于使用restful风格,实现跨服务数据传输。
Eureka服务注册与发现
eureka服务注册中心实现
1.构建注册中心服务模块
写一个服务注册模块,这部分是server端
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.suda</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.suda</groupId>
<artifactId>springcloud-eureka</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false # 是否向注册中心注册自己
fetch-registry: false
service-url: # 监控页面
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# defaultZone: http://localhost:7001/eureka/
EurekaServer_7001.java主函数,注意注解
package com.suda.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);
}
}
2.将provider加进注册中心
向pom.xml中添加erreka依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
departmentController类中添加服务查看功能
@Autowired
private DiscoveryClient client;
// 获取注册的微服务信息
@GetMapping("/department/discovery")
public Object discovery(){
List<String> services = client.getServices();
System.out.println(services);
// 得到一个具体的微服务信息
List<ServiceInstance> instances = client.getInstances("springcloud-provider");
for (ServiceInstance instance : instances) {
System.out.println(instance.getHost()+"\t"+instance.getInstanceId()+"\t"+instance.getUri());
}
return client;
}
在主类上加注解
package com.suda.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册
@EnableDiscoveryClient //服务发现
public class DepartmentProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DepartmentProvider_8001.class, args);
}
}
application.yml添加注解
server:
port: 8001
mybatis:
type-aliases-package: com.suda.springcloud.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
# configuration:
# map-underscore-to-camel-case: true
spring:
application:
name: springcloud-provider
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&useSSL=true&useLegacyDatetimeCode=false&serverTimezone=America/New_York
username: spark
password: 123456
#eureka
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
instance-id: springcloud-provider #修改eureka上默认描述信息
info:
app.name: springcloud-eureka
效果
可见spring单体项目到springcloud只需要几个注解和几行代码,体现出非侵入性。
注册中心集群
制作三个注册中心模块并互相绑定
修改eureka对应application.yml配置
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false # 是否向注册中心注册自己
fetch-registry: false
service-url: # 监控页面
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# defaultZone: http://localhost:7001/eureka/
defaultZone: http://localhost:7002/eureka/,http://localhost:7003/eureka/
修改provider/application.yml配置
#eureka
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
instance:
instance-id: springcloud-provider #修改eureka上默认描述信息
info:
app.name: springcloud-eureka
启动三个注册中心和provider服务
问题,发现使用三个中心都使用localhost,三个中心无法互相发现,而且只有1-2个注册中心能发现服务,猜测是三台主机都叫localhost导致,故修改如下
修改主机host
修改eureka的application.yml
server:
port: 7003
eureka:
instance:
hostname: eureka7003
client:
register-with-eureka: false # 是否向注册中心注册自己
fetch-registry: false
service-url: # 监控页面
defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/
# defaultZone: http://localhost:7001/eureka/
修改provider的application.yml
server:
port: 8001
mybatis:
type-aliases-package: com.suda.springcloud.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
# configuration:
# map-underscore-to-camel-case: true
spring:
application:
name: springcloud-provider
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&useSSL=true&useLegacyDatetimeCode=false&serverTimezone=America/New_York
username: spark
password: 123456
#eureka
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider #修改eureka上默认描述信息
info:
app.name: springcloud-eureka
展示,注册中心可以互相发现,服务也可以发现
Eureka和Zookeeper
zookeeper保证的cp,容忍服务可用性差,但一致性必须高,
Ribbon
Ribbon实现负载均衡
在消费端修改
pom.xml新增依赖
<!--ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
application.yml 配置eureka
server:
port: 80
#eureka config
eureka:
client:
register-with-eureka: false # 不需要注册消费端
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
configBean加注解
@Configuration
public class ConfigBean {
//注册 RestTemplate
@Bean
// 配置实现负载均衡
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
departmentConsumer.java 加注解
@SpringBootApplication
@EnableEurekaClient
public class DepartmentConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DepartmentConsumer_80.class,args);
}
}
controller/DepartmentConsumerController.java 修改访问地址
package com.suda.springcloud.controller;
import com.suda.springcloud.pojo.Department;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DepartmentConsumerController {
//RestTemplate ... register it in spring,
//使用restful风格,从消费端访问生产端,获取数据。
@Autowired
private RestTemplate restTemplate;
//单机用这个访问地址
// private static final String rest_url_prefix = "http://localhost:8001";
// 通过ribbon实现负载均衡,通过服务名来访问,实现动态访问
private static final String rest_url_prefix = "http://springcloud-provider";
@RequestMapping("/consumer/department/get/{id}")
public Department get(@PathVariable("id")Long id){
return restTemplate.getForObject(rest_url_prefix+"/department/get/"+id, Department.class);
}
@RequestMapping("/consumer/department/add")
public boolean add(Department department){
return restTemplate.postForObject(rest_url_prefix+"/department/add",department, Boolean.class);
}
@RequestMapping("/consumer/department/getall")
public List<Department> getList(){
return restTemplate.getForObject(rest_url_prefix+"/department/list",List.class);
}
}
模拟负载均衡
再造两个生产者,对应数据库db01,db02
复制目录出现问题,导致8002,8003运行找不到主类
启动七个服务:
结果:
默认轮询查找,且找不到三
注意:在mapper中写增删查改的时候,不要加上数据库名,否则查找的数据库单一。
自定义Ribbon负载均衡算法
不能喝主类在一个目录,不然会被springscan到,所以可以放上一级目录
Feign
服务熔断
测试
1.拷贝一份provider,新建hystrix
2.导入pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
3.controller/DepartmentController.java只写两个方法测试
package com.suda.springcloud.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.suda.springcloud.pojo.Department;
import com.suda.springcloud.service.IDepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class DepartmentController {
@Autowired
private IDepartmentService departmentService;
@GetMapping("/department/get/{id}")
@HystrixCommand(fallbackMethod = "hystrixGetById")
public Department getDepartmentById(@PathVariable("id") Long id) {
Department department = departmentService.queryById(id);
if(department == null){
throw new RuntimeException("the user is not exist");
}
return department;
}
public Department hystrixGetById(@PathVariable("id") Long id) {
return new Department().setDepartmentId(id)
.setDepartmentName("without the user information_hystrix")
.setDbSource("no this database in MySql");
}
// @PostMapping("/department/add")
// public boolean addDepartment(Department department){
// return departmentService.addDepartment(department);
// }
//
// @GetMapping("/department/get/{id}")
// public Department addDepartmentById(@PathVariable("id") Long id){
// return departmentService.queryById(id);
// }
//
// @GetMapping("/department/list")
// public List<Department> queryDepartmentById ( ){
// return departmentService.queryAll();
// }
@Autowired
private DiscoveryClient client;
// 获取注册的微服务信息
@GetMapping("/department/discovery")
public Object discovery(){
List<String> services = client.getServices();
System.out.println(services);
// 得到一个具体的微服务信息
List<ServiceInstance> instances = client.getInstances("springcloud-provider");
for (ServiceInstance instance : instances) {
System.out.println(instance.getHost()+"\t"+instance.getInstanceId()+"\t"+instance.getUri());
}
return client;
}
}
4.主类+熔断注解
package com.suda.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker //开启熔断
public class DepartmentProvider_hystrix {
public static void main(String[] args) {
SpringApplication.run(DepartmentProvider_hystrix.class, args);
}
}
结果:
服务降级
服务降级是指某个服务不可用后,返回较友好的提示界面,并且不影响用户访问其他服务,需要自定义类,并实现之前写的IDepartmentClientService接口
package com.suda.springcloud.service;
import com.suda.springcloud.pojo.Department;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
//服务降级
@Component
public class DepartmentClientServiceFallbackFactory implements FallbackFactory {
public IDepartmentClientService create(Throwable throwable) {
return new IDepartmentClientService() {
public Department queryById(Long id) {
return new Department().setDepartmentId(id)
.setDepartmentName("客户端提供了降级操作,这个服务已关闭")
.setDbSource("没有数据");
}
public List<Department> queryAll() {
return (List<Department>) new Department().setDepartmentId((long) 0)
.setDepartmentName("客户端提供了降级操作,这个服务已关闭")
.setDbSource("没有数据");
}
public Department addDepartment(Department department) {
return new Department().setDepartmentId((long) 0)
.setDepartmentName("客户端提供了降级操作,这个服务已关闭")
.setDbSource("没有数据");
}
};
}
}
HystrixDashboard
配置监控客户端
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.suda</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.suda</groupId>
<artifactId>springcloud-consumer-dashboard</artifactId>
<dependencies>
<dependency>
<groupId>com.suda</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
<!--ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
application.xml
server:
port: 9001
Dashboard9001
package com.suda.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard
@EnableCircuitBreaker
public class Dashboard9001 {
public static void main(String[] args) {
SpringApplication.run(Dashboard9001.class, args);
}
}
provider端
pom新增
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
启动函数
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker
public class DepartmentProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DepartmentProvider_8001.class, args);
}
@Bean
public ServletRegistrationBean HystrixMetricsStreamServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
bean.addUrlMappings("/actuator/hystrix.stream");
return bean;
}
}
Zuul路由网关
实战
新建路由模块
pom新增配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
application。yml
server:
port: 9527
spring:
application:
name: springcloud-zuul
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: zuul9527.com
prefer-ip-address: true
info:
app.name: springcloud
company.name: com.suda
zuul:
routes:
departments:
serviceId: springcloud-provider
path: /mydept/* #修改url路径
# ignored-services: springcloud-provider #不能用这个路径访问
# ignored-services: "*"
启动类
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
SpringCloud Config
参考自狂神