springcloud记录篇3-springcloud客户端ribbon和feign
来源:互联网 发布:浙江师范行知学院 编辑:程序博客网 时间:2024/05/21 21:20
一 。客户端介绍
在springcloud中发布的服务一般为http服务 使用http服务客户端即可调用 最底层的http协议是使用它tcp协议实现 清晰理解http协议请求响应模型可以
使用Socket来进行请求 这种方式开发成本太大,java.net包提供了 HttpURLConnection类来处理http协议 该类可以发送get和post请求,但是没有自动重连以及
自动解析 以及不同数据格式的处理 功能 apache提供的 common-net 机 github开源项目 okhttp 都可以很好的解决以上问题 springboot 引入这两个框架
二 。ribbon配置和演示
ribbon所有的配置 需要在spring的配置文件中 <client>.ribbon.* 也就是调用的客户端类全路径 .ribbon.*
*的部分可以参考 github官网https://github.com/Netflix/ribbon/wiki/Getting-Started
比如ribbon的连接超时(sample-client.ribbon.ConnectTimeout=3000) 读超时(sample-client.ribbon.ReadTimeout=1000)
ribbon使用RestTemplate实现http调用 提供了客户端负载均衡的能力
1》引入ribbon maven依赖
groupid org.springframework.cloud artifactid spring-cloud-starter-ribbon2》测试调用和负载均衡
测试环境为 《springcloud记录篇2-服务注册和发现》文章中的环境
eurekaserver 本机ip为 192.168.88.20 主机名 mymaster 端口 8761 这里为了简单就不开启eurekaserver的从服务eurekabackup服务提供和服务消费配置 eurekapub 本机ip 192.168.88.20 端口8086 应用名称 idserver eurekapub 本机ip 192.168.88.20 端口8085 应用名称 idserver eurekaconsumer 本机ip 192.168.88.20 端口8888因为客户端eurekaconsumer(订阅者)需要调用eurekapub提供的服务 eurekapub需要做负载处理 开启两台设置不同端口
》》eurekapub配置如下
server: port: 8086eureka: client: serviceUrl: defaultZone: http://jiaozi:jiaozi123@mymaster:8761/eureka/#每个服务必须有一个唯一的应用名称 该服务的负载均衡 可以通过相同名称的一组服务 做集群 spring: application: name: idserver运行主类
package cn.et;import java.util.UUID;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;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.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * 服务提供则 @EnableDiscoveryClient 将当前服务注册到Eureka服务器 * @author jiaozi * */@EnableDiscoveryClient(autoRegister=true)@SpringBootApplication@RestControllerpublic class EurekapubApplication {@RequestMapping("/getId")public String getId() {return UUID.randomUUID().toString();}public static void main(String[] args) {SpringApplication.run(EurekapubApplication.class, args);}}同一个项目将 application.yml中server.port=8085 后启动 然后 改成8086后启动
访问localhost:8761 输入eurekaserver的用户名和密码
》》eurekaconsume配置如下
主类 EurekaconsumerApplication
package cn.et;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.client.loadbalancer.LoadBalanced;import org.springframework.cloud.netflix.ribbon.RibbonClient;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.client.RestTemplate;import cn.et1.RuleSetting;@SpringBootApplication@EnableDiscoveryClient(autoRegister=true)@Configuration@RibbonClient(value="IDSERVER") //表示使用ribbon客户端 value表示发布方的服务名称public class EurekaconsumerApplication {@LoadBalanced //启动负载均衡 @Bean RestTemplate restTemplate() { return new RestTemplate(); }public static void main(String[] args) {SpringApplication.run(EurekaconsumerApplication.class, args);}}添加Controller类测试TestController
package cn.et;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;import com.netflix.appinfo.InstanceInfo;import com.netflix.discovery.EurekaClient;import com.netflix.loadbalancer.IRule;@RestControllerpublic class TestController {@AutowiredEurekaClient client;@Autowired private RestTemplate restTemplate;/** * 直接通过服务方地址 http://localhost:8080/getId 调用这种方式没有集群 * //@LoadBalanced不能添加 * @return */@RequestMapping("invokeService")public String invokeService() {String uuid=restTemplate.getForObject("http://localhost:8080/getId", String.class);return uuid;}/** * 通过在eureka server注册的 应用名称 直接来访问 * @LoadBalanced必须添加 * @return */@RequestMapping("invokeServiceBalance")public String invokeServiceBalance() {String uuid=restTemplate.getForObject("http://IDSERVER/getId",String.class);//getid是服务发布方提供的http方法return uuid;}@Autowired private LoadBalancerClient loadBalancer;/** * 启动多个发布者 端口不一致 程序名相同 * 使用 * @LoadBalanced必须添加 * @return */@RequestMapping("choosePub")public String choosePub() {StringBuffer sb=new StringBuffer();for(int i=0;i<=10;i++) {ServiceInstance ss=loadBalancer.choose("IDSERVER");//从两个idserver中选择一个 这里涉及到选择算法sb.append(ss.getUri().toString()+"<br/>");}return sb.toString();}}以上定义LoadBalancerClient 可以用于测试选择的服务器的算法 负载的算法的类需要实现
IRule
接口 以下列表摘自网络策略名
策略描述
BestAvailableRule
选择一个最小的并发请求的server
AvailabilityFilteringRule
过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值)
WeightedResponseTimeRule
根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。
RetryRule
对选定的负载均衡策略机上重试机制。
RoundRobinRule
roundRobin方式轮询选择server
RandomRule
随机选择一个server
ZoneAvoidanceRule
复合判断server所在区域的性能和server的可用性选择server
ribbon默认的配置类为 RibbonClientConfiguration 其中配置IRule的bean为@Bean@ConditionalOnMissingBeanpublic IRule ribbonRule(IClientConfig config) {if (this.propertiesFactory.isSet(IRule.class, name)) {return this.propertiesFactory.get(IRule.class, config, name);}ZoneAvoidanceRule rule = new ZoneAvoidanceRule();rule.initWithNiwsConfig(config);return rule;}默认使用的是ZoneAvoidanceRule 代码第一行判断是否存在IRule的规则 说明可以自己来设置
自定义ribbon负载规则两种方式
方式1 自动bean 覆盖IRule (假设这里永远选择第一个服务器)
创建类 MyRule类 继承AbstractLoadBalancerRule
package cn.et1;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 {@Overridepublic Server choose(Object key) {//获取负载均衡接口ILoadBalancer lb=getLoadBalancer();//获取所有的服务器 包括不可用和可用List<Server> allServers=lb.getAllServers();//获取所有可用服务器 List<Server> avaServers=lb.getReachableServers();//永远返回第一台return avaServers.get(0);}private IClientConfig clientConfig=null;@Overridepublic void initWithNiwsConfig(IClientConfig arg0) {this.clientConfig=arg0;}}创建bean定义类RuleSetting(该类不能被扫描到 要么去掉 @Configuration注解要么放在 非main方法的包和子包中 否则会出错)
package cn.et1;import org.springframework.context.annotation.Bean;import com.netflix.client.config.IClientConfig;import com.netflix.loadbalancer.IRule;import com.netflix.loadbalancer.RandomRule;public class RuleSetting {@Beanpublic IRule ribbonRule(IClientConfig config) {return new MyRule(); //这里是自定义的规则//return new RandomRule();//也可以返回自带一些规则 比如随机选择等}}
修改主类 EurekaconsumerApplication注解RibbonClinet
@RibbonClient(value="IDSERVER",configuration=RuleSetting.class)访问 客户端 choosePub 发现随机选择10次发现每次都只出现第一个服务器的ip和端口
方式2 使用配置文件设置规则的类(开始IDSERVER表示是调用发布者名称)
IDSERVER.ribbon.NFLoadBalancerRuleClassName=cn.et1.MyRule
其他具体参考(http://cloud.spring.io/spring-cloud-static/Dalston.SR4/multi/multi_spring-cloud-ribbon.html)
三 。feign配置和演示
feign同是github上开源项目可以轻松实现 调用http服务,是一个声明式的rest调用框架 项目地址为:https://github.com/OpenFeign/feign
以下实例测试环境 同 ribbon 不同的是 将ribbon调用换成了feign
springboot封装了ribbon将原始ribbon的用法替换成了springmvc的方式
feign具体用法参考 http://cloud.spring.io/spring-cloud-static/Dalston.SR4/multi/multi_spring-cloud-feign.html
修改服务发布方 eurekapub 提供一个get和post的服务
1》发布方修改
启动主类 EurekapubApplication
package cn.et;import java.util.UUID;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;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.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * 服务提供则 @EnableDiscoveryClient 将当前服务注册到Eureka服务器 * @author jiaozi * */@EnableDiscoveryClient(autoRegister=true)@SpringBootApplication@RestControllerpublic class EurekapubApplication {@RequestMapping("/getId")public String getId() {return UUID.randomUUID().toString();}/** * 测试get方法 * @param id * @return */@GetMapping("/getUser/{id}")public User getId(@PathVariable String id) {User user=new User();user.setUserName("zs_"+id);user.setPassword("ls_"+id);return user;}/** * 测试post方法 post方法获取内容 必须添加@RequestBody注解否则无法获取 * @param user * @return */@PostMapping("/saveUser")public User getId(@RequestBody User user) {return user;}public static void main(String[] args) {SpringApplication.run(EurekapubApplication.class, args);}}测试的用户类
package cn.et;import lombok.Data;@Datapublic class User {private String userName;private String password;}这里用到了 lombok 引用maven依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId></dependency>找到jar包后 运行 java -jar lombok-1.16.18.jar 选择eclipse 安装目录 自动安装插件 该包原理是 通过插件 伪造get和set方法 不添加get set 可以使用get和
set方法 编译时自动添加get和set方法
修改完成后 依次启动 8085和8086两个实例
2》订阅方eurekaconsume修改
》》springmvc调用方式
拷贝发布方的User到到当前项目
添加调用客户端类TestClient
package cn.feign;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;@FeignClient("idserver") //使用FeignClient 告知发布方的应用名称 默认使用ribbon进行负载均衡public interface TestClient {@RequestMapping(method = RequestMethod.GET, value = "/getUser/{id}") //因为是调用必须明确告诉是GET方式传入的参数是idpublic User getId(@PathVariable("id") String id) ;@RequestMapping(method = RequestMethod.POST, value = "/saveUser",consumes="application/json")public User saveUser(@RequestBody User user) ;//post请求必须添加@RequestBody}添加Controller类
package cn.feign;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;import org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.netflix.loadbalancer.Server;@RestControllerpublic class TestController {@Autowiredprivate TestClient client;@Autowiredprivate LoadBalancerClient flb;@RequestMapping("chooseFeign")public String chooseFeign() {StringBuffer sb=new StringBuffer();for(int i=0;i<=10;i++) {ServiceInstance ss=flb.choose("IDSERVER");sb.append(ss.getUri()+"<br/>");}return sb.toString();}/** * 使用Feign调用client的get方式 * @return */@RequestMapping("getUser")public User getUser(String id) {User user=client.getId(id);return user;}/** * 使用Feign调用client的post方法 * @return */@RequestMapping("saveUser")public User saveUser(User user) {User muser=client.saveUser(user);return muser;}}添加主类EurekaconsumerApplication
package cn.feign;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.client.loadbalancer.LoadBalanced;import org.springframework.cloud.netflix.feign.EnableFeignClients;import org.springframework.cloud.netflix.feign.FeignClientsConfiguration;import org.springframework.cloud.netflix.ribbon.RibbonClient;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.client.RestTemplate;import cn.et1.FeignConf;import cn.et1.RuleSetting;@SpringBootApplication@EnableDiscoveryClient(autoRegister=true)@EnableFeignClients(defaultConfiguration=FeignClientsConfiguration.class)@Configurationpublic class EurekaconsumerApplication {public static void main(String[] args) {SpringApplication.run(EurekaconsumerApplication.class, args); }}启动服务 测试get方法(consume端口 设置8888)
http://localhost:8888/getUser?id=20
成功调用输出
{"userName":"zs_20","password":"ls_20"}
启动服务 测试get方法(consume端口 设置8888)
http://localhost:8888/saveUser?userName=zs&password=123456
成功调用输出
{"userName":"zs","password":"123456"}
》》feign调用方式
具体feign的语法参考https://github.com/OpenFeign/feign
添加一个配置类 告知springcloud 使用feign原始的操作方式
package cn.et1;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import feign.Contract;import feign.Logger;@Configurationpublic class FeignConf {@Beanpublic Contract feignContract() {return new feign.Contract.Default(); //返回原始的解析方式} }
添加客户端调用类 TestClient2
package cn.feign;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import cn.et1.FeignConf;import feign.Param;import feign.RequestLine;//这里注意一点 name 如果设置了一次 他的配置类 所有相同name的都会使用这个配置类 这里为了掩饰直接用url 给个特殊的名字 名字只是标识@FeignClient(name="mytest",url="http://localhost:8086",configuration=FeignConf.class)public interface TestClient2 {@RequestLine("GET /getUser/{id}")public User getId(@Param("id") String id) ;@RequestLine("POST /saveUser")public User saveUser(User user) ;}添加 TestController1 用于测试
package cn.feign;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;import org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.netflix.loadbalancer.Server;@RestControllerpublic class TestController {@Autowiredprivate TestClient2 client2;/** * 使用Feign调用 * @return */@RequestMapping("getUser2")public User getUser2(String id) {User user=client2.getId(id);return user;}/** * 使用Feign调用 * @return */@RequestMapping("saveUser2")public User saveUser2(User user) {User muser=client2.saveUser(user);return muser;}}
主类相同 然后运行 同样访问方式 访问 测试ok
》》日志添加
springboot允许客户端在调用http协议时打印调用http日志信息
application.yml中添加(logging.level.声明调用的客户端类 只支持debug一种方式)
logging.level.cn.feign.TestClient2: DEBUG
修改 FeignConf类 添加打印所有日志
package cn.et1;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import feign.Contract;import feign.Logger;@Configurationpublic class FeignConf {@Beanpublic Contract feignContract() {return new feign.Contract.Default();} @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; }}启动访问 发现日志成功输出
- springcloud记录篇3-springcloud客户端ribbon和feign
- Springcloud consul + ribbon\feign
- SpringCloud学习:Eureka、Ribbon和Feign
- SPRINGCLOUD(EUREKA+RIBBON+FEIGN+HYSTRIX)
- springcloud(第八篇)springcloud feign
- springcloud(第八篇)springcloud feign
- springcloud(第六篇)springcloud ribbon
- SpringCloud第三篇-Feign
- SpringCloud第二篇-Ribbon:
- SpringCloud---Ribbon客户端负载均衡
- SpringCloud(六)springcloud feign
- springcloud(第七篇)springcloud ribbon with eureka
- springcloud入门系列(2)-Feign、Ribbon实现Rest接口请求和负载均衡
- 3.springcloud中使用Ribbon和Feign调用服务以及服务的高可用
- SpringCloud 声明式REST客户端Feign
- SpringCloud Feign参数传递问题记录
- SpringCloud | Feign如何整合Ribbon进行负载均衡的?
- SpringCloud系列(3)---Netfilx-Ribbon
- [BZOJ]1899: [Zjoi2004]Lunch 午餐 DP
- STL库中的stack和queue及其模拟实现
- springmvc学习笔记(19)-RESTful支持
- 类加载
- Java的值传递,没有引用传递
- springcloud记录篇3-springcloud客户端ribbon和feign
- Knights
- JaveEE请求转发和重定向的区别
- C++ 数据封装
- Mybatis的基本配置和使用
- Hash表(哈希表、散列表)
- springmvc学习笔记(20)-拦截器
- 初探Construct2(一)
- DNS域名解析的基本过程