一.Ribbon
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。
参考文档:http://cloud.spring.io/spring-cloud-static/Dalston.SR5/single/spring-cloud.html#spring-cloud-ribbon 第16节
项目环境:https://blog.youkuaiyun.com/wufewu/article/details/84646382
Ribbon调用
Main方法处添加负载均衡
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
RestTemplate的用法
RestTemplate的四种请求:
GET请求 getForEntity
POST请求 postForEntity
PUT请求 put
DELETE请求 delete
客户端请求:
Book book = new Book();
book.setName(“红楼梦”);
ResponseEntity<Book> responseEntity = restTemplate.postForEntity(“http://服务名/路径", book, Book.class);
return responseEntity.getBody();
服务端接收
@PostMapping(value = "/getbook2")
public Book book2(@RequestBody Book book) {
}
其中具体的例子可以查看:https://blog.youkuaiyun.com/wufewu/article/details/84646382 里面的SPRINGCLOUD_USERUI模块
其中默认的是RoundRobinRule(轮循查询),如果想要更改算法,直接在Main方法添加一个Bean类,如:
@Bean
// 支持负载均衡功能(默认使用Ribbon实现负载均衡)
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
// 指定负载均衡算法
// 所有调用的微服务都想是同一个规则就放在这里
// 全局配置
@Bean
public RandomRule randomRule() {
return new RandomRule();
}
public static void main(String[] args) {
new SpringApplicationBuilder(UserUi.class).web(true).run(args);
}
解释:我将负载均衡算法改为了一个RandomRule算法(随机算法),
模拟环境:在注册中心建立一个微服务的两个实例,然后在客户端建立一个调用微服务的方法的方法,然后输出结果。这里就不展示了
注意:在Main方法里更改算法,所有的调用微服务的算法都会变成更改后的算法
建立自定义的负载均衡规则:
定义规则类
package com.ps.rule;
import java.util.List;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
public class MyRule extends AbstractLoadBalancerRule{
@Override
public Server choose(Object key) {
// 取到当前的负载均衡器,由父类提供 可以拿到对应的要调用微服务后的服务器
ILoadBalancer loadBalancer = this.getLoadBalancer();
// 取到所有可以访问的服务器
List<Server> reachableServers = loadBalancer.getReachableServers();
return reachableServers.get(0);
}
@Override
public void initWithNiwsConfig(IClientConfig arg0) {
// TODO Auto-generated method stub
}
}
然后在Main方法指定算法:
@Bean
public IRule rhle() {
return new MyRule();
}
解释:在这里调用微服务的实例只能调用第一个
当调用微服务不使用全局配置,即调用指定的微服务时是随机,调用其他的微服务是默认(轮徇)的
自定义类:
@RibbonClient(value="USERSERVICE",configuration=MyRule.class)
public class MyRule {
@Bean
public IRule randomRul() {
return new RoundRobinRule();
}
}
然后在application.yml资源文件中加:
# 放在这里是指针对不同的微服务调用不同的负载均衡规则
USERSERVICE:
ribbon:
NFLoadBalancerRuleClassName: com.ps.rule.MyRule
解释:
USERSERVICE:指微服务的名字
com.ps.rule.MyRule:指定义的类的路径
二.Feign简介
Feign是从Netflix中分离出来的轻量级项目,能够在类接口上添加注释,成为一个REST API 客户端,(面向对象,更优雅,更适合普通的开发者人员)
参考文档:http://cloud.spring.io/spring-cloud-static/Dalston.SR5/single/spring-cloud.html#spring-cloud-feign 第17节
项目环境:https://blog.youkuaiyun.com/wufewu/article/details/84646382
我现在根据项目环境来演示一下feign的调法,查看项目环境中的SPRINGCLOUD_USERSERVICE模块,添加一个EmpController.java与一个实体类,如下:
代码如下:
EmpController.java
package com.ps.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.ps.entity.Emp;
import com.ps.entity.Result;
@RestController
public class EmpController {
@GetMapping("/emp/{id}")
public Result queryEmp(@PathVariable("id") String id) {
Emp emp = new Emp();
emp.setId("1");
emp.setName("张三");
Result re = new Result();
List<Emp> list = new ArrayList<>();
list.add(emp);
re.setCode(1);
re.setData(list);
return re;
}
// post请求因为参数带有对象,所以必须添加@RequestBody
@PostMapping("/emp")
public Result saveEmp(@RequestBody Emp emp) {
Result re = new Result();
re.setCode(1);
re.setMsg("增加应该成功了");
return re;
}
@DeleteMapping("/emp/{id}")
public Result delEmp(@PathVariable String id) {
Result re = new Result();
re.setCode(1);
re.setMsg("删除应该成功了");
return re;
}
@PutMapping("/emp/{id}")
public Result delEmp(@PathVariable String id,@RequestBody Emp emp) {
Result re = new Result();
re.setCode(1);
re.setMsg("修改应该成功了");
return re;
}
}
Emp.java
@Data
public class Emp {
private String id;
private String name;
}
然后再在项目中加一个模块(方便演示)SPRINGCLOUD_USERUI_FEIGN,如:
在pom.xml文件添加依赖:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 小辣椒 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<!-- 开发者工具 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- 导入Feign依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
application.yml资源文件:
#界面一般是80端口
server:
port: 80
#给登录微服务设置一个名字
spring:
application:
name: useruifeign
eureka:
instance:
prefer-ip-address: true
hostname: localhost
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka/
entity包下的两个实体类:
Emp.java:
@Data
public class Emp {
private String id;
private String name;
}
Result.java
@Data
public class Result {
private int code;
private String msg;
private List<Emp> data;
}
EmpFeign.java
// 客户端的接口根远程service做了绑定,假如在这个类跳用queryEmp方法就相当与调用远程微服务
// 指定要调用的微服务
@FeignClient(name="USERSERVICE")
public interface EmpFeign {
@GetMapping("/emp/{id}")
public Result queryEmp(@PathVariable("id") String id) ;
@PostMapping("/emp")
public Result saveEmp(@RequestBody Emp emp) ;
@DeleteMapping("/emp/{id}")
public Result delEmp(@PathVariable("id") String id) ;
@PutMapping("/emp/{id}")
public Result delEmp(@PathVariable("id") String id,@RequestBody Emp emp) ;
}
UserUiFeing.java
@SpringBootApplication
// 启用eureka的服务
@EnableEurekaClient
// 表示启用Feign
@EnableFeignClients
public class UserUiFeign {
public static void main(String[] args) {
new SpringApplicationBuilder(UserUiFeign.class).web(true).run(args);
}
}
controlloer包下的EmpcController.java
@RestController
public class EmpcController {
@Autowired
EmpFeign empFeign;
@GetMapping("/query")
public List<Emp> query() {
String id = "1";
Result queryEmp = empFeign.queryEmp(id);
return queryEmp.getData();
}
@GetMapping("/save")
public String save() {
Result queryEmp = empFeign.saveEmp(new Emp());
return queryEmp.getMsg();
}
@GetMapping("/del")
public String del() {
Result delEmp = empFeign.delEmp("1");
return delEmp.getMsg();
}
@GetMapping("/aaa")
public String a() {
String a = empFeign.a();
return a;
}
}
运行结果: