2

上一篇写到关于SpringCloudEureka的相关知识:SpringCloud服务治理Eureka。我们实现的服注册中心,以及服务提供者。接下来记录关于服务消费,以及客户端负载均衡器Ribbon的简单使用和配置。在使用Ribbon之前,先看看怎么调用服务吧。

基础的服务消费

服务提供者

在上一篇的基础之上,创建一个service-user的微服务。这个微服我使用了h2数据库来保存数据,所以需要在配置文件中添加关于数据库的配置以及在pom文件中添加依赖,<!--more-->
application.yml

server:
  port: 40000
spring:
  application:
    name: user-service
#===========================================================
#   数据库配置
#===========================================================
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
    generate-ddl: false
  datasource:
    platform: h2
    schema: classpath:schema.sql
    data: classpath:data.sql
#===========================================================
#   eureka配置
#===========================================================
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8888/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${server.port}

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

然后编写数据库文件初始化数据;
schema.sql

DROP TABLE user if  EXISTS ;
create table user (
  id int generated by DEFAULT  as IDENTITY,
  username VARCHAR (40),
  age INT(3),
  PRIMARY KEY (id)
);

data.sql

insert into user (id,username,age) values (1,'张三',20);
insert into user (id,username,age) values (2,'李四',25);
insert into user (id,username,age) values (3,'王五',23);
insert into user (id,username,age) values (4,'赵六',30);

User实体类,这里使用了lombok工具

@Entity
@Data
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column
    private String username;
    @Column
    private int age;
}

然后创建UserRepositoryUserController,在UserController中添加一个根据id查询的接口:

@Autowired
private UserRepository userRepository;
@GetMapping("/user/{id}")
public User findById(@PathVariable("id") Long id){
    return userRepository.findOne(id);
}

SpringBoot入口类上添加@EnableEurekaClient注解

@EnableEurekaClient
@SpringBootApplication
public class UserApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

最终的项目结构:

启动项目,访问:http://localhost:40000/user/1

服务消费

这里直接修改上一篇service-article服务,用service-article服务来调用service-user服务。所以需要修改service-article,新增User对象和ArticleController,在ArticleController中添加一个查询接口。
这里调用服务都是使用RestTemplate,所以先在入口内中注册注册RestTemplate

@SpringBootApplication
@EnableEurekaClient
public class ArticleApplication {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ArticleApplication.class, args);
    }
}

User实体,可以直接拷贝user微服务的实体类去掉注解即可,因为这里不是持久化对象。

@Data
public class User implements Serializable {

    private Long id;
    private String username;
    private int age;
}

ArticleController

@RestController
public class ArticleController {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/a/u/{id}")
    public User getUser(@PathVariable("id") Long id){
        return restTemplate.getForObject("http://localhost:40000/user/{1}",User.class,id);
    }
}

启动服务,访问:http://localhost:30000/a/u/2

使用Ribbon

介绍

SpringCloudRibbon是一个基于HTTP和TCP的客户端负载均衡工具。是基于Netfix Ribbon实现的。SpringCloud将其封装,可以让我们轻松的将面向服务的REST模板自动转换成客户端负载均衡的服务调用。

使用

修改article-service
添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

在注册RestTemplate方法上添加@LoadBalanced注解开启客户端负载均衡,然后修改请求的URL,直接使用服务名请求,这里能够直接使用服务名,是因为在SpringCloudRibbon中有一个拦截器,他能够在实际调用的时候自动的选取服务实例,并将实际请求的ip地址替换这里的服务名。详细介绍可以查看DD大佬的书:<<SpringCloud微服务实战>>

@GetMapping("/a/u/{id}")
public User getUser(@PathVariable("id") Long id){
    return restTemplate.getForObject("http://USER-SERVICE:40000/user/{1}",User.class,id);
}

最后为了测试负载均衡,我们需要开启多个USER-SERVICE服务实例;在USER-SERVICE中添加application-pree1.ymlapplication-pree2.yml,具体配与application.yml一样,只要修改server.port,这里分别是40001和40002。然后打包服务,分别启动两个服务

java -jar user-0.0.1-SNAPSHOT.jar --spring.profiles.active=pree1

java -jar user-0.0.1-SNAPSHOT.jar --spring.profiles.active=pree2

在注册中心可以看到三个USER-SERVICE服务:

最后启动ARTICLE-SERVICE,并访问接口。刷新几次页面,发现三个服务都会打印数据库语句,这里调用方式为线性轮询

Ribbon的配置

当我们在SpringBoot项目中添加SpringCloudRibbon以后,SpringBoot会为我们自动化配置Ribbon,有些时候自动化配置是无法满足需要的。我们都知道在SpringBoot中我们可以使用两种配置属性的方法:使用java config方式和在配置文件中配置。

使用配置类的方式

创建UserServiceConfig,该类不能在启动时候被扫描到,所以我们需要将该类放到SpringBoot入口类的上一层路径下。

@Configuration
public class UserServiceConfig {
    /**
     *将服务检查策略改为PingUrl
     * @return
     */
    @Bean
    public IPing ribbonPing(){
        return new PingUrl();
    }
    /**
     * 将负载均衡的策略改为随机选取服务实例
     * @return
     */
    @Bean
    public IRule ribbonRule(){
        return new RandomRule();
    }
}

然后创建RibbonConfig,这里@RibbonClients注解是可以指定多个RibbonClient,而@RibbonClient注解则是指定那个哪个服务使用哪个配置类

@Configuration
@RibbonClients({
        @RibbonClient(name = "user-service",configuration = UserServiceConfig.class),
})
public class RibbonConfig {
}

在appplication.yml中配置

在配置文件中配置时候我们也可以配置全局的和指定客户端方式配置

  1. 全局配置,只需要使用ribbon.<key>=<value>,key客户端配置参数名,value为对应的参数值
  2. 指定客户端配置,使用<client>.ribbon.<key>=<value>,这里的client为指定的服务名。下面为user-service指定负载均衡策略:
USER-SERVICE:
  ribbon:
    RulePredicateClasses: com.netflix.loadbalancer.RandomRule

更多关于key的配置信息可以查看com.netflix.client.config.CommonClientConfigKey


作为SpringCloud学习笔记,可能有很多地方不好。望指出!!!

源码地址:https://gitee.com/wqh3520/spring-cloud-1-9/tree/master/

原文地址:SpringCloud学习之Ribbon


wqh8522
125 声望5 粉丝

Java开发工程师