都是客户端负载均衡技术。
Feign : 面向接口形式
Ribbon : 面向rest风格
Feign 实现负载均衡步骤
实体类模块
导入feign
<!-- feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
提供接口访问服务
@FeignClient() 注解
添加到interface 之后,标识该接口能被客户端访问,用来调用服务端的方法
package com.wang.springcloud.service;
import com.wang.springcloud.pojo.Dept;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Component
@FeignClient("SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptConsumerService {
//这里是服务端提供的访问路径
@RequestMapping("/dept/add")
public boolean add(Dept dept);
@RequestMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") int id);
@RequestMapping("/dept/list")
public List<Dept> queryAll();
}
客户端模块
pom.xml
导入实体类,eureka,feign 等依赖
<?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>spring-cloud</artifactId>
<groupId>com.wang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer-dept-80</artifactId>
<dependencies>
<!-- 实体类-->
<dependency>
<groupId>com.wang</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka配置-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!-- ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!-- 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
配置文件
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 负载均衡bean注册
package com.wang.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 ConfigBean {
@Bean
// 配置负载均衡请求 不仅ribbon 使用,feign也会用到
@LoadBalanced //Ribbon
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
服务端发送请求的controller
package com.wang.springcloud.controller;
import com.wang.springcloud.pojo.Dept;
import com.wang.springcloud.service.DeptConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
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 DeptConsumerController {
//消费者,不应该有service层
//RestTemplate
// 面向接口调用服务端服务,接口来自实体类模块
@Autowired
private DeptConsumerService deptConsumerService =null;
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return this.deptConsumerService.add(dept);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") int id){
return this.deptConsumerService.get(id);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> queryAll(){
return this.deptConsumerService.queryAll();
}
}
启动类
需要开启eureka 和feign
@EnableEurekaClient @EnableFeignClients(basePackageClasses = DeptConsumerService.class)
package com.wang.springcloud;
import com.wang.springcloud.service.DeptConsumerService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackageClasses = DeptConsumerService.class)
//@ComponentScan(value = "com.wang.springcloud")
public class DeptConsumerFeign {
public static void main(String[] args) {
SpringApplication.run(DeptConsumerFeign.class,args);
}
}
测试
问题
404
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Apr 17 19:57:29 GMT+08:00 2020
There was an unexpected error (type=Internal Server Error, status=500).
status 404 reading DeptConsumerService#queryAll(); content: {"timestamp":1587124649605,"status":404,"error":"Not Found","message":"Not Found","path":"/consumer/dept/list"}
前台通过客户端访问报了这个错误,原因是在api应用中写接口的时候,把url写成客户端的了,应该是服务端的才对。。
package com.wang.springcloud.service;
import com.wang.springcloud.pojo.Dept;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Component
@FeignClient("SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptConsumerService {
//这里是服务端提供的访问路径
@RequestMapping("/dept/add")
public boolean add(Dept dept);
@RequestMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") int id);
@RequestMapping("/dept/list")
public List<Dept> queryAll();
}
Load balancer does not have available server for client:
com.netflix.client.ClientException: Load balancer does not have available server for client: SPRINGCLOUD-PROVIDER-DEPT
at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:483) ~[ribbon-loadbalancer-2.2.5.jar:2.2.5]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184) ~[ribbon-loadbalancer-2.2.5.jar:2.2.5]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.2.5.jar:2.2.5]
错误的原因:由于之前ribbon 显式使用了RestTemplate 的bean,所以有配置。但是这边其实式隐式使用。还是需要注入的。
package com.wang.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 ConfigBean {
@Bean
// 配置负载均衡请求 不仅ribbon 使用,feign也会用到
@LoadBalanced //Ribbon
public RestTemplate restTemplate(){
return new RestTemplate();
}
}