Ribbon是一个负载均衡客户端,可以很好的控制http和tcp的一些行为,一般都是Ribbon
搭配Feign
一起使用;Feign默认集成了ribbon
feign
的依赖compile('io.github.openfeign:feign-core:9.5.0')
compile('io.github.openfeign:feign-jackson:9.5.0')
compile('io.github.openfeign:feign-ribbon:9.5.0')
build.gradle
文件内容:
apply plugin: 'java'
apply plugin: 'eclipse'
group = 'org.wjw.standardribbon'
version = '1.0.0-SNAPSHOT'
sourceCompatibility = 1.8
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
repositories {
mavenLocal()
maven{ url "http://SVN:8081/nexus/content/groups/public"}
mavenCentral()
jcenter()
}
dependencies {
compile('org.slf4j:slf4j-api')
compile('org.slf4j:slf4j-log4j12:1.7.25')
compile('commons-logging:commons-logging:1.2')
compile('io.github.openfeign:feign-core:9.5.0')
compile('io.github.openfeign:feign-jackson:9.5.0')
compile('io.github.openfeign:feign-ribbon:9.5.0')
}
执行: gradle init --type java-library
RemoteService
接口中定义了一个名为getAdd
的方法package org.wjw.standardribbon.service;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
public interface RemoteService {
/**
GET /add?a=1&b=2 HTTP/1.1
Content-Type: application/json
Accept: application/json
User-Agent: Java/1.8.0_121
Host: 192.168.2.113:8861
Connection: keep-alive
*/
@Headers({ "Content-Type: application/json", "Accept: application/json" })
@RequestLine("GET /add?a={a}&b={b}")
int getAdd(@Param("a") int a, @Param("b") int b);
}
ribbon.properties
,该文件位于src/main/resources
下#所有的key都以service-one开头,表明这些配置项作用于名为service-one的服务
service-one.ribbon.MaxAutoRetries=1
service-one.ribbon.MaxAutoRetriesNextServer=1
service-one.ribbon.OkToRetryOnAllOperations=true
service-one.ribbon.ServerListRefreshInterval=2000
service-one.ribbon.ConnectTimeout=3000
service-one.ribbon.ReadTimeout=3000
service-one.ribbon.listOfServers=192.168.2.113:8861,192.168.2.114:8861
service-one.ribbon.EnablePrimeConnections=false
config-server.ribbon.MaxAutoRetries=1
config-server.ribbon.MaxAutoRetriesNextServer=1
config-server.ribbon.OkToRetryOnAllOperations=true
config-server.ribbon.ServerListRefreshInterval=2000
config-server.ribbon.ConnectTimeout=3000
config-server.ribbon.ReadTimeout=3000
config-server.ribbon.listOfServers=192.168.2.114:7001
config-server.ribbon.EnablePrimeConnections=false
现在来看
ribbon.properties
中的配置项 所有的key都以service-one
开头,表明这些配置项作用于名为service-one
的服务.其实就是与之前绑定RemoteService
接口的URL地址的schema相对应.重点看
ribbon.properties
文件里的service-one.ribbon.listOfServers
配置项,该配置项指定了服务生产端的真实地址. 与RemoteService接口绑定的URL地址是"http://service-one/",在调用时会被替换为
http://192.168.2.113:8861/
或http://192.168.2.114:8861/
,再与接口中@RequestLine
指定的地址进行拼接,得到最终请求地址. 本例中最终请求地址为http://192.168.2.113:8861/add
或http://192.168.2.114:8861/add
由于使用的ribbon,所以feign不再需要配置超时时长,重试策略.ribbon提供了更为完善的策略实现.
package org.wjw.cloud.service.controller;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ComputeController {
private final Logger logger = Logger.getLogger(getClass());
@Autowired
private DiscoveryClient client;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public int add(@RequestParam int a, @RequestParam int b) {
int r = a + b;
ServiceInstance instance = client.getInstances(client.getServices().get(0)).get(0);
logger.info("/add, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", result:" + r);
return r;
}
}
将服务生产端部署到
Eureka
中,在8861端口运行
package org.wjw.standardribbon;
import org.wjw.standardribbon.model.User;
import org.wjw.standardribbon.service.PropService;
import org.wjw.standardribbon.service.RemoteService;
import com.netflix.client.ClientFactory;
import com.netflix.client.config.IClientConfig;
import com.netflix.config.ConfigurationManager;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.ribbon.LBClient;
import feign.ribbon.LBClientFactory;
import feign.ribbon.RibbonClient;
public class StdRibbon {
public static void main(String[] args) throws Exception {
ConfigurationManager.loadPropertiesFromResources("ribbon.properties");
RibbonClient client = RibbonClient.builder().lbClientFactory(new LBClientFactory() {
@Override
public LBClient create(String clientName) {
IClientConfig config = ClientFactory.getNamedConfig(clientName);
ILoadBalancer lb = ClientFactory.getNamedLoadBalancer(clientName);
ZoneAwareLoadBalancer zb = (ZoneAwareLoadBalancer) lb;
zb.setRule(new RandomRule());
return LBClient.create(lb, config);
}
}).build();
/*
重点看ribbon.properties文件里的service-one.ribbon.listOfServers配置项,该配置项指定了服务生产端的真实地址.
与RemoteService接口绑定的URL地址是"http://service-one/",
在调用时会被替换为http://192.168.2.113:8861/或http://192.168.2.114:8861/,再与接口中@RequestLine指定的地址进行拼接,得到最终请求地址
本例中最终请求地址为"http://192.168.2.113:8861/add"或"http://192.168.2.114:8861/add"
*/
RemoteService service = Feign.builder().client(client).encoder(new JacksonEncoder())
.decoder(new JacksonDecoder()).target(RemoteService.class, "http://service-one/");
/**
* 调用测试
*/
for (int i = 1; i <= 10; i++) {
int result = service.getAdd(1, 2);
System.out.println("result:" + result);
}
}
}
首先利用
com.netflix.config.ConfigurationManager
读取配置文件ribbon.properties
,该文件位于src/main/resources
下. 重点在于通过RibbonClient.create()使得Feign对象获得了Ribbon的特性.之后通过encoder,decoder设置编码器与解码器,并通过target方法将之前定义的接口RemoteService与一个URL地址http://service-one/
进行了绑定.
执行: gradlew bootRun
默认端口号是:8080
输入:
http://127.0.0.1:8080/add?a=1&b=2
返回:
3