服务注册与发现
zookeeper
在CentOS7上安装zookeeper,并将zookeeper作为服务注册中心,程序可以通过服务名找到对应的主机,相当于一个容器,将服务放在容器中,其他在容器中的服务就能够找到该服务
8004端口配置服务
服务别名——注册zookeeper到注册中心名称
spring: application: name: cloud-provider-payment cloud: zookeeper: connect-string: 192.168.10.102:2181
2. **设置访问接口**```javapackage com.atguigu.springcloud.controller;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.UUID;@RestController@Slf4jpublic class PaymentController{@Value("${server.port}")private String serverPort;@RequestMapping(value = "/payment/zk")public String paymentzk(){return "springcloud with zookeeper: "+serverPort+"\t"+ UUID.randomUUID().toString();}}
配置maven环境 ```java <?xml version=”1.0” encoding=”UTF-8”?>
cloud2020 com.atguigu.springcloud 1.0-SNAPSHOT 4.0.0 cloud-consumerzk-order80 org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-zookeeper-discovery org.apache.zookeeper zookeeper org.apache.zookeeper zookeeper 3.4.9 org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test
<a name="D0y0G"></a>
### 80端口配置消费者
1. **配置yml文件**
```java
server:
port: 80
spring:
application:
name: cloud-consumer-order
cloud:
#注册到zookeeper地址
zookeeper:
connect-string: 192.168.10.102:2181
- 添加配置类 ```java package com.atguigu.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;
@Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
3. **设置接口**
```java
package com.atguigu.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderZKController
{
public static final String INVOKE_URL = "http://cloud-provider-payment"; //通过名字去寻找对应的服务
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/zk")
public String paymentInfo()
{
String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
return result;
}
}
consul
- 下载解压完成后为exe文件,可以通过
consul.exe --version查看版本号 - 启动
consul agent -dev - 通过
[http://localhost:8500/](http://localhost:8500/ui/dc1/services)访问前端页面
配置8006端口服务端
spring: application: name: consul-provider-payment
consul注册中心地址
cloud: consul: host: localhost port: 8500 discovery:
#hostname: 127.0.0.1
service-name: ${spring.application.name}
2. **编写接口**
```java
package com.atguigu.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
@Slf4j
public class PaymentController
{
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/consul")
public String paymentConsul()
{
return "springcloud with consul: "+serverPort+"\t "+ UUID.randomUUID().toString();
}
}
配置maven环境 ```java <?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"><artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version>4.0.0 cloud-consumerconsul-order80
<dependencies>
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<a name="XoxOX"></a>
### 80端口消费者
1. 编写yml配置文件
```java
###consul服务端口号
server:
port: 80
spring:
application:
name: cloud-consumer-order
####consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
#hostname: 127.0.0.1
service-name: ${spring.application.name}
- 编写配置类 ```java package com.atguigu.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;
@Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
3. 编写接口
```java
package com.atguigu.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderConsulController
{
public static final String INVOKE_URL = "http://consul-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/consul")
public String paymentInfo()
{
String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul",String.class);
return result;
}
}
服务调用
Ribbon负载均衡
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。
Ribbon核心组件IRule
IRule:根据特定算法中从服务列表中选取一个要访问的服务
| 对象 | 算法 |
|---|---|
| com.netflix.loadbalancer.RoundRobinRule | 轮询 |
| com.netflix.loadbalancer.RandomRule | 随机 |
| com.netflix.loadbalancer.RetryRule | 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务 |
| WeightedResponseTimeRule | 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择 |
| BestAvailableRule | 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务 |
| AvailabilityFilteringRule | 先过滤掉故障实例,再选择并发较小的实例 |
| ZoneAvoidanceRule | 默认规则,复合判断server所在区域的性能和server的可用性选择服务器 |
替换负载均衡算法
细节:官方文档明确给出了警告:这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。
- 新建package:com.atguigu.myrule
- 新建MySelfRule规则类 ```java package com.atguigu.myrule;
import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class MySelfRule { @Bean public IRule myRule() { return new RandomRule();//定义为随机 } }
3. 主启动类添加注解:`//@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration=MySelfRule.class)`
<a name="KjXdY"></a>
## OpenFeign服务接口调用
**OpenFeign=Rest+Ribbon**<br />Feign是一个声明式的Web服务客户端,让编写Web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可<br />[官网](https://github.com/spring-cloud/spring-cloud-openfeign)<br />**Feign能干什么**<br />Feign旨在使编写Java Http客户端变得更容易。<br />前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。<br />**Feign集成了Ribbon**<br />利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
<a name="zvuXF"></a>
### 使用
1. 添加maven坐标
```java
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 修改yml文件 ```java server: port: 80
eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
3. 主启动类
```java
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients // 使用该注解菜可以使用OpenFeign
public class OrderFeignMain80
{
public static void main(String[] args)
{
SpringApplication.run(OrderFeignMain80.class,args);
}
}
- 新建接口业务类 ```java package com.atguigu.springcloud.service;
import com.atguigu.springcloud.entities.CommonResult; import com.atguigu.springcloud.entities.Payment; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable;
@Component @FeignClient(value = “CLOUD-PAYMENT-SERVICE”) public interface PaymentFeignService { @GetMapping(value = “/payment/get/{id}”) CommonResult getPaymentById(@PathVariable(“id”) Long id); }
5. 控制层Controller
```java
package com.atguigu.springcloud.controller;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentFeignService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class OrderFeignController
{
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping(value = "/consumer/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id)
{
return paymentFeignService.getPaymentById(id);
}
}
超时控制和日志打印功能
package com.atguigu.springcloud.cfgbeans;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import feign.Logger;
@Configuration
public class FeignConfig
{
@Bean
Logger.Level feignLoggerLevel()
{
return Logger.Level.FULL;
}
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
#设置feign客户端超时时间
#springCloud默认开启支持ribbon
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
logging:
level:
# feign日志以什么级别监控哪个接口
com.atguigu.springcloud.service.PaymentFeignService: debug
