用注解和配置文件的方式引用Spring Cloud整合的Ribbon

1.准备工作

为了实现负载均衡的效果,我们使用Spring Cloud服务管理框架Eureka简单示例(三)底部的源代码稍加修改使用(如果下面的内容看不懂,可以先查看上面这篇博文),eureka-provider需要启动两个实例,修改启动类ProviderApp的main()方法,通过在控制台输入不同的端口(8082和8083)来启动实例:

package com.init.springCloud;

import java.util.Scanner;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class ProviderApp {

	public static void main(String[] args) {
		@SuppressWarnings("resource")  
        Scanner scan = new Scanner(System.in);  
        String port = scan.nextLine();  
        new SpringApplicationBuilder(ProviderApp.class).properties("server.port=" + port).run(args);  
	}

}

为了区分服务调用者使用的是哪一个服务,为Person类添加info属性:

package com.init.springCloud;

import lombok.Data;

@Data
public class Person {

	private Integer id;			//主键ID
	private String name;		//姓名
	private String info;		//信息,根据URL地址查看服务的来源  
	
}

同时修改控制器ProviderController,把请求的参数传输到Person类的info属性里:

package com.init.springCloud;

import javax.servlet.http.HttpServletRequest;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProviderController {

	@RequestMapping(value = "/search/{id}", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public Person searchPerson(@PathVariable Integer id, HttpServletRequest request){
		Person person = new Person();
		person.setId(id);
		person.setName("Spirit");
		person.setInfo(request.getRequestURL().toString());
		return person;
	}
	
}

之后,依次启动euraka-server,两个eureka-provider服务(8082和8083端口),eureka-consumer,访问:http://localhost:8081/router,验证我们的配置是否成功,成功的标志是轮询调用两个服务返回结果。

 

2.使用注解引用Ribbon

在eureka-consumer的com.init.springCloud包下新建MyRule类,来自Ribbon负载均衡器详细介绍(七)中创建的规则,新增一段打印文字,用来显示是否使用了我们的规则,完整代码如下:

package com.init.springCloud;  
  
import java.util.List;  
import java.util.Random;  
  
import com.netflix.loadbalancer.ILoadBalancer;  
import com.netflix.loadbalancer.IRule;  
import com.netflix.loadbalancer.Server;  
  
public class MyRule implements IRule {  
  
    private ILoadBalancer lb;  
      
    @Override  
    public Server choose(Object key) {  
    	System.out.println("这是自定义的规则");
        Random random = new Random();  
        Integer num = random.nextInt(10);//在0-9这10个随机数里取值  
        //获取传输负载均衡器里所有的服务  
        List<Server> servers = lb.getAllServers();  
        if(num>7){//返回8082端口服务  
            return chooseServerByPort(servers,8082);  
        }  
        //返回8083端口服务  
        return chooseServerByPort(servers,8083);  
    }  
      
    private Server chooseServerByPort(List<Server> servers,Integer port){  
        for (Server server : servers) {  
            if(server.getPort() == port){  
                return server;  
            }  
        }  
        return null;  
    }  
  
    @Override  
    public void setLoadBalancer(ILoadBalancer lb) {  
        this.lb = lb;  
    }  
  
    @Override  
    public ILoadBalancer getLoadBalancer() {  
        return lb;  
    }  
  
} 

之后创建一个MyConfig类,用于返回我们自定义的负载均衡规则:

package com.init.springCloud;

import org.springframework.context.annotation.Bean;

import com.netflix.loadbalancer.IRule;

public class MyConfig {

	@Bean
	public IRule getMyRule(){
		return new MyRule();
	}
	
}

再新建MyLoadBalanceClient类,使用我们的配置去调用自定义规则:

package com.init.springCloud;

import org.springframework.cloud.netflix.ribbon.RibbonClient;

@RibbonClient(name = "eureka-provider", configuration = MyConfig.class)
public class MyLoadBalanceClient {

}

这个时候重启eureka-consumer项目,多次访问:http://localhost:8081/router,我们就会看到调用8083服务明显比8082服务的次数多,控制台也显示调用了我们的自定义规则:

3.使用配置文件引用Ribbon

将MyLoadBalanceClient类的@RibbonClient注解注释掉,然后在eureka-consumer的application.yml的文件中配置我们自定义的规则,上一篇博客有讲过,配置规则是:"客户端名称"."命名空间"."属性名",我们需要配置的规则是:NFLoadBalancerRuleClassName,完整的application.yml配置如下:
server:
  port: 8081

spring:
  application:
    name: eureka-consumer
    
eureka-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.init.springCloud.MyRule

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
重新启动eureka-consumer项目,多次访问:http://localhost:8081/router,我们就会看到调用8083服务明显比8082服务的次数多,控制台同样也显示调用了我们的自定义规则。

使用Spring Cloud封装好的Ribbon

Spring Cloud将Ribbon整合之后,使用了一个叫做LoadBalancerClient的客户端来做服务调用,这个客户端有一个choose的方法,传入服务的ID就可以依据规则从对应的服务实例中获取到服务,在com.init.springCloud下的ConsumerController控制器新建getMyDefinedService方法并访问http://localhost:8081/service:

	@Autowired
	private LoadBalancerClient client;
	
	@GetMapping(value = "/service")
	@ResponseBody
	public void getMyDefinedService(){
		ServiceInstance instance = client.choose("eureka-provider");
		System.out.println("地址:"+instance.getHost()+",端口:"+instance.getPort());
	}

可以看到LoadBalancerClient使用了我们自定义的负载均衡规则:

我们也可以去探寻一下LoadBalancerClient底层默认使用了什么样的负载均衡器,又使用了什么样的负载规则。引入SpringClientFactory,获取默认的负载均衡器类和对应的规则方法,同样在ConsumerController控制器里添加方法:

	@Autowired
	private SpringClientFactory factory;
	
	@GetMapping(value = "/rule")
	@ResponseBody
	public void getMyDefinedRule(){
		ILoadBalancer balancer = factory.getLoadBalancer("default");
		System.out.println("Spring Cloud默认使用的均衡器:"+balancer);
		
		DynamicServerListLoadBalancer balancer2 = (DynamicServerListLoadBalancer)factory.getLoadBalancer("default");
		System.out.println("默认使用的规则:"+balancer2.getRule().getClass().getName());
		
		DynamicServerListLoadBalancer balancer3 = (DynamicServerListLoadBalancer)factory.getLoadBalancer("eureka-provider");
		System.out.println("eureka-provider使用的规则:"+balancer3.getRule().getClass().getName());
	}

访问:http://localhost:8081/rule,控制台输出了Spring Cloud整合Ribbon默认使用的负载均衡器和负载均衡规则,以及eureka-provider使用的我们自定义负载均衡规则。

这里Spring Cloud默认使用的ZoneAvoidanceRule规则,在上一篇博客中也提到了,它是指使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone的所有server,AvailabilityPredicate用于过滤掉连接数过多的Server。

如果我们要覆盖默认的负载均衡规则,只需要在配置文件中将Ribbon配置的客户端名称改为“default”就OK了:

default:
  ribbon:
    NFLoadBalancerRuleClassName: com.init.springCloud.MyRule

源码点击这里

最后,大家有什么不懂的或者其他需要交流的内容,也可以进入我的QQ讨论群一起讨论:654331206

Spring Cloud系列:

Spring Cloud介绍与环境搭建(一)

Spring Boot的简单使用(二)

Spring Cloud服务管理框架Eureka简单示例(三)

Spring Cloud服务管理框架Eureka项目集群(四)

Spring Cloud之Eureka客户端健康检测(五)

Netflix之第一个Ribbon程序(六)

Ribbon负载均衡器详细介绍(七)

Spring Cloud中使用Ribbon(八)

具有负载均衡功能的RestTemplate底层原理(九)

OpenFeign之第一个Feign程序(十)

OpenFeign之feign使用简介(十一)

Spring Cloud中使用Feign(十二)

Netflix之第一个Hystrix程序(十三)

Netflix之Hystrix详细分析(十四)

Spring Cloud中使用Hystrix(十五)

Netflix之第一个Zuul程序(十六)

Spring Cloud集群中使用Zuul(十七)

Netflix之Zuul的进阶应用(十八)

消息驱动之背景概述(十九)

消息中间件之RabbitMQ入门讲解(二十)

消息中间件之Kafka入门讲解(二十一)

Spring Cloud整合RabbitMQ或Kafka消息驱动(二十二)

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐