环境:
SpringCloud: Hoxton.SR9
SpringBoot:2.3.5.RELEASE
其他依赖:2.2.6.RELEASE
相关依赖
服务者:pring-cloud-starter-netflix-eureka-client
Eureka:spring-cloud-starter-netflix-eureka-server
消费者+Ribbon:spring-cloud-starter-netflix-eureka-client
spring-cloud-starter-netflix-ribbon
Feign: spring-cloud-starter-openfeign
Hystrix:spring-cloud-starter-netflix-hystrix
spring-cloud-starter-netflix-hystrix-dashboard
zuul:spring-cloud-starter-netflix-zuul
数据库(这里要建三个不同的数据库,模拟负载均衡)
sql
CREATE TABLE `dept` (
`dno` bigint(20) NOT NULL AUTO_INCREMENT,
`dname` varchar(60) DEFAULT NULL,
`db_source` varchar(60) DEFAULT NULL,
PRIMARY KEY (`dno`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='部门表';
数据
INSERT INTO dept (dname, db_source)VALUES ('开发部',DATABASE());
INSERT INTO dept (dname, db_source)VALUES ('市场部',DATABASE());
INSERT INTO dept (dname, db_source)VALUES ('研发部',DATABASE());
INSERT INTO dept (dname, db_source)VALUES ('人事部',DATABASE());
数据库
父工程(父依赖)
<!-- 打包方式-->
<packaging>pom</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<!-- springcloud依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
springcloud-api
依赖:
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
</dependencies>
实体类(供其他服务调用)
@Data
@NoArgsConstructor
@Accessors(chain = true) //支持链式写法
public class Dept {
private Long dno;
private String dname;
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
}
整合Eureka
两个组件:Eureka Server和Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
容灾机制(没啥用)
在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
服务提供者(springcloud-provide-dept-9001)
依次搭建三个,连接不同的数据库,模拟负载均衡
包结构
依赖
<dependency>
<groupId>com.sun</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--数据库-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- Eureka -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--完善监控消息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
application.yml
server:
port: 9001
#mybatis配置
mybatis:
type-aliases-package: com.sun.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
#配置
spring:
datasource:
username: root
password: qwe123456
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
application:
name: spring-clout-provide-dept
##eureka配置,将服务提供者注册到注册中心
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springclout-provide-dept-9001
#info配置
info:
app.name: ajie-spring-cloud
company.name: localhost:9001
代码(mybatis)
Mapper层
DeptMapper
@Mapper
@Repository
public interface DeptMapper {
Boolean insert(Dept dept);
Dept getById(Long dno);
List<Dept> all();
}
DeptMapper.xml(接口实现类)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace=绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.sun.mapper.DeptMapper">
<insert id="insert" parameterType="Dept">
insert into db01.dept(dname, db_source)
values (#{dname},DATABASE());
</insert>
<select id="getById" resultType="Dept" parameterType="Long">
select * from dept where dno=#{dno}
</select>
<select id="all" resultType="Dept">
select * from dept;
</select>
</mapper>
service层
DeptService接口
public interface DeptService {
Boolean insert(Dept dept);
Dept getById(Long dno);
List<Dept> all();
}
实现类
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
DeptMapper deptMapper;
@Override
public Boolean insert(Dept dept) {
return deptMapper.insert(dept);
}
@Override
public Dept getById(Long dno) {
return deptMapper.getById(dno);
}
@Override
public List<Dept> all() {
return deptMapper.all();
}
}
controller层
DeptController
@RestController
public class DeptController {
@Autowired
DiscoveryClient client;
@Autowired
DeptServiceImpl service;
@PostMapping("/insert")
public boolean insert(Dept dept){
return service.insert(dept);
}
@GetMapping("/ById/{dno}")
public Dept get(@PathVariable("dno") Long dno){
Dept byId = service.getById(dno);
return byId;
}
@GetMapping("/")
public List<Dept> all(){
return service.all();
}
//得到注册中心微服务的信息
@GetMapping("/discovery")
public Object discovery(){
//获取微服务列表的清单
List<String> services = client.getServices();
System.out.println("微服务清单:"+services);
//获取具体微服务信息,通过id进行查询
List<ServiceInstance> instances = client.getInstances("SPRING-CLOUT-PROVIDE-DEPT-9000");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost()+"\t"+
instance.getPort()+"\t"+
instance.getUri()+"\t"+
instance.getServiceId()
);
}
return this.client;
}
}
然后再主类上开始
@SpringBootApplication
@EnableEurekaClient //开启Eureka注解,启动之后服务提供者就会自动注册到注册中心
public class SpringcloudProvideDept9001Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudProvideDept9001Application.class, args);
}
}
运行就会循环寻找注册中心注册
注册中心(springcloud-eureck-7001)
这个也可以搭建多个,模拟一个注册中心崩掉之后还有其他注册中心进行服务
Eureka的注册中心是要自己配置
依赖
<!--eureka服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
application.yml
server:
port: 7001
#Eureka配置
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false # 表示是否向eureka注册中心注册自己
fetch-registry: false #fetch-registry如果为false,表明自己为注册中心
service-url: # 注册中心
#单机:http://${eureka.instance.hostname}:${server.port}/eureka/
#集群(关联)
defaultZone: http://eureka7003.com:7003/eureka/,http://eureka7002.com:7002/eureka/
然后再主类上开启eureka服务就是ok了
一个注册中心就搭好了
@SpringBootApplication
@EnableEurekaServer //开启eureka服务
public class SpringcloudEureck7001Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudEureck7001Application.class, args);
}
}
效果
服务消费者(springcloud-consume-8011)
通过注册中心调用服务提供的service层
依赖
<dependency>
<groupId>com.sun</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
application.yml
#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/
server:
port: 8011
代码
config配置
实现负载均衡的一些算法(轮询和随机)
@Configuration
public class DeptConsumerConfig {
// 配置负载均衡实现RestTemplate
@Bean
@LoadBalanced //开启负载均衡 默认轮询算法
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@Bean //随机算法
public IRule rom() {
return new RandomRule();
}
}
controller层
@RestController
public class DeptConsumerController {
//通过restTemplate 发送http请求
@Autowired
private RestTemplate restTemplate; //提供多种便捷访问远程http服务的方法,简称Restful服务模板
private static final String REST_URL_PREFIX = "http://SPRING-CLOUT-PROVIDE-DEPT";
@RequestMapping("/all")
public List<Dept> all() {
return restTemplate.getForObject(REST_URL_PREFIX, List.class);
}
@RequestMapping("/dno/{dno}")
public Dept getById(@PathVariable("dno") Long dno) {
return restTemplate.getForObject(REST_URL_PREFIX + "/ById/" + dno, Dept.class);
}
@PostMapping("/insert")
public Boolean insert(Dept dept) {
return restTemplate.postForObject(REST_URL_PREFIX + "/insert", dept, Boolean.class);
}
}
然后再主类上开启
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudConsume8011Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudConsume8011Application.class, args);
}
}
运行即可
效果:
整合ribbon
依赖
<!--ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
上面的服务提供者依葫芦画瓢搭建多个,然后连接不同的数据库,都注册到注册中心,然后服务消费者多次调用,才看数据库,就差不多了
整合Feign
这东西我不会,一直报404,给我整抑郁了
整合Hystrix(springcloud-provide-dept-hystrix-9001)
和上面的服务提供差不多,不过这个加了熔断机制
包结构
依赖
<dependency>
<groupId>com.sun</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--数据库-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- Eureka -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--完善监控消息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
application.yml
server:
port: 9001
#mybatis配置
mybatis:
type-aliases-package: com.sun.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
config-location: classpath:mybatis/mybatis-config.xml
#配置
spring:
datasource:
username: root
password: qwe123456
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
application:
name: spring-clout-provide-dept
##eureka配置,将服务提供者注册到注册中心
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springclout-provide-dept-hystrix-9001
prefer-ip-address: true #设置为true 可以显示ip
#info配置
info:
app.name: ajie-spring-cloud
company.name: localhost:9001
代码:
Mapper层和Service层都一样的,就略
controller
@RestController
public class DeptController {
@Autowired
DeptServiceImpl service;
@GetMapping("/ById/{dno}")
@HystrixCommand(fallbackMethod = "hystrixGet")
public Dept get(@PathVariable("dno") Long dno){
Dept byId = service.getById(dno);
if(byId ==null){
throw new RuntimeException("dno=>"+dno+"不存在");
}
return byId;
}
// //备选
public Dept hystrixGet(@PathVariable("dno")Long dno){
return new Dept()
.setDno(dno)
.setDname("dno=>"+dno+"不存在")
.setDb_source("no this database in MYSQL");
}
@GetMapping("/")
public List<Dept> all(){
return service.all();
}
}
在主类上开启
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker //添加对熔断的支持
public class SpringcloudProvideDeptHystrix9001Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudProvideDeptHystrix9001Application.class, args);
}
}
效果:
正常
模拟出错(查询不存在的值)
监控(springcloud-consume-hystrix-dashboard-8013)
hysrix自带的流量监控,不过只能对加了熔断注解的方法继续监视
依赖
<dependency>
<groupId>com.sun</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--hystrix监控-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
application.yml
确保监控中心能寻找到流
# 添加hystrix监控配置
hystrix:
dashboard:
proxy-stream-allow-list: "*"
在主类上开始监控
@SpringBootApplication
@EnableHystrixDashboard //开启监控
public class SpringcloudConsumeHystrixDashboard8013Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudConsumeHystrixDashboard8013Application.class, args);
}
}
一个监控中心就搭建完了
启动运行http://localhost:8013/hystrix
效果:
在添加熔断的主类下添加以下代码,方便被监控
// 增加servlet监控 只有hystrix的依赖才能被监控
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
这里只能监控添加熔断的服务端
整合Zuul(springcloud-zuul-6001)
通过一个同意的入口进行访问
依赖
<dependency>
<groupId>com.sun</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--hystrix监控-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
application.yml
server:
port: 6001
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: springcloud-zuul-6001
prefer-ip-address: true
info:
app.name: ajie
company.naeme: ajie-springcloud
#zuul配置,把微服务名称进行替换,防止暴露
zuul:
routes:
mydept.serviceId: spring-clout-provide-dept
mydept.path: /mydept/**
ignored-services: spring-clout-provide-dept # 不能使用该路径访问 隐藏微服务
在主类上开启
@SpringBootApplication
@EnableZuulProxy //开启zuul路由
public class SpringcloudZuul6001Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudZuul6001Application.class, args);
}
}
通过统一的http://localhost:6001/mydept/ById/3
进行访问,在application.yml配置文件中进行设置
差不多就是这些了