非Spring环境下的Ribbon+Feign使用宝典

Java框架

浏览数:21

2020-6-1

AD:资源代下载服务

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')
}

创建一个 Java Application 项目

执行: gradle init --type java-library

  • Feign声明式服务消费端接口
    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/addhttp://192.168.2.114:8861/add

由于使用的ribbon,所以feign不再需要配置超时时长,重试策略.ribbon提供了更为完善的策略实现.

  • 本例中,服务端是一个简单的spring mvc,实现如下:
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端口运行

  • Java启动APP
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/进行了绑定.

启动Spring Boot程序

执行: gradlew bootRun

默认端口号是:8080

在浏览器里测试

输入:http://127.0.0.1:8080/add?a=1&b=2

返回: 3

作者:白石