Spring Cloud + Feign实现微服务负载路由

项目的启动顺序为
spring-cloud-eureka 提供注册服务:节点两个【resumer-eurake-9001、resumer-eurake-9002】
微服务(提供服务):节点两个【resumer-user、resumer-user2forTest】
spring-cloud-feign调用微服务(服务消费端):【resumer-feign】

1 spring-cloud-eureka
1.1 resumer-eurake-9001
resumer-eurake-9001配置文件application.yml:

eureka:
  instance:
    hostname: eureka9001.com
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
       defaultZone: http://192.168.0.104:9002/eureka/
# 关闭注册中心的自我保护机制,防止已关闭的实例无法从注册中心剔除
#eureka.server.enable-self-preservation=false
server:
  port: 9001
logging:
  config: classpath:logback.xml

启动类:EurekaApplication9001.java

package com.asiainfo.resumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
//激活eureka的服务端
@EnableEurekaServer
public class EurekaApplication9001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication9001.class, args);
    }
}

1.2 resumer-eurake-9002
resumer-eurake-9002配置文件application.yml:

eureka:
  instance:
    hostname: eureka9002.com
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
       defaultZone: http://192.168.0.104:9001/eureka/
# 关闭注册中心的自我保护机制,防止已关闭的实例无法从注册中心剔除
#eureka.server.enable-self-preservation=false
server:
  port: 9002
logging:
  config: classpath:logback.xml

启动类:EurekaApplication9002.java 同EurekaApplication9001.java 一样。

2 微服务(提供服务):节点两个【resumer-user、resumer-user2forTest】
2.1 resumer-user 配置
resumer-user 配置文件yml:

server:
   port: 8002
mybatis:
   config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径
   mapper-locations:
   - classpath:mybatis/mapper/**/*.xml # mapper映射文件
   type-aliases-package: com.asiainfo.resumer # 别名类所在包
spring:
   application:
      name: resumer-user #微服务的名字
   datasource:
      driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
      type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
      url: jdbc:mysql://localhost:3306/cloudagenttest # 数据库名称
      username: root
      password: root
      dbcp2:
         initial-size: 5 # 初始化连接数
         max-total: 5 # 最大连接数
         max-wait-millis: 200 # 等待连接获取的最大超时时间
         min-idle: 5 # 数据库连接池的最小维持连接数
eureka:
   client:
      service-url:
         defaultZone: http://localhost:9001/eureka,http://localhost:9002/eureka
         instance:
            instance-id: resumer-user8002 #自定义服务名称信息
            prefer-ip-address: true #访问路径可以显示IP地

info:
   app.name: resumer-user
   company.name: ASIAINFO
   build.artifactId: $project.artifactId$
   build.version: $project.version$

注意:resumer-user #微服务的名字,将被spring-cloud-feign调用微服务(服务消费端)【resumer-feign】调用。
启动类ProviderApplication.java

package com.asiainfo.resumer;

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

@SpringBootApplication
@EnableEurekaClient
public class ProviderApplication {

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

控制层controller-UserController.java类

package com.asiainfo.resumer.controller;
import java.util.List;
import com.asiainfo.resumer.User;
import com.asiainfo.resumer.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
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;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @Autowired
    private UserService service; 
    /**
     * 测试方法
     * <p>Title: getUserTest</p>  
     * <p>Description: </p>  
     * @param id
     * @return
     */
    @CrossOrigin(origins = "*")// 支持跨域
    @RequestMapping(value="/gettest/{id}", method=RequestMethod.GET)
    public User getUserTest(@PathVariable("id") int id){
        User user = service.getUser(id);
        return user;
    }
}

业务层Service-(包括接口和实现) 和数据层dao

package com.asiainfo.resumer.service;
import java.util.List;
import com.asiainfo.resumer.User;
public interface UserService {
    public User getUser(int id);
}

package com.asiainfo.resumer.service.impl;
import java.util.List;
import com.asiainfo.resumer.User;
import com.asiainfo.resumer.dao.UserDao;
import com.asiainfo.resumer.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao; 
    @Override
    public User getUser(int id) {
        User user = userDao.getUser(id);
        System.out.println("microservice-provider微服务在响应客户端请求……");
        System.out.println("user : " + user);
        return user;
    } 
}
package com.asiainfo.resumer.dao;
import java.util.List;
import com.asiainfo.resumer.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserDao {
    public User getUser(int id);
}

数据层mybatis关联信息
UserMapper.xml【resources/mybatis/mapper/UserMapper.xml】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.asiainfo.resumer.dao.UserDao">
    <select id="getUser" resultType="User" parameterType="int">
        select * from user where ID=#{id}
    </select>
</mapper>

mybatis.cfg.xml【resources/mybatis/mybatis.cfg.xml】

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 开启二级缓存 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

数据库use表脚本:

CREATE TABLE `user` (
  `ID` int(10) NOT NULL,
  `NAME` varchar(50) DEFAULT NULL,
  `AGE` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
insert into `user` (`ID`, `NAME`, `AGE`) values('1','CJ','30');

2.2 resumer-user2forTest yml配置

server:
   port: 8003
mybatis:
   config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径
   mapper-locations:
   - classpath:mybatis/mapper/**/*.xml # mapper映射文件
   type-aliases-package: com.asiainfo.resumer # 别名类所在包
spring:
   application:
      name: resumer-user #微服务的名字
   datasource:
      driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
      type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
      url: jdbc:mysql://localhost:3306/cloudagenttest # 数据库名称
      username: root
      password: root
      dbcp2:
         initial-size: 5 # 初始化连接数
         max-total: 5 # 最大连接数
         max-wait-millis: 200 # 等待连接获取的最大超时时间
         min-idle: 5 # 数据库连接池的最小维持连接数
eureka:
   client:
      service-url:
         defaultZone: http://localhost:9001/eureka,http://localhost:9002/eureka
         instance:
            instance-id: resumer-user8003 #自定义服务名称信息
            prefer-ip-address: true #访问路径可以显示IP地

info:
   app.name: resumer-user
   company.name: ASIAINFO
   build.artifactId: $project.artifactId$
   build.version: $project.version$

注意:resumer-user #微服务的名字 同 resumer-user节点名称保持一致。

3 spring-cloud-feign调用微服务(服务消费端):【resumer-feign】
3.1 配置文件yml

server:
  port: 7001

eureka:
  client:
    register-with-eureka: false#不在Eureka上注册与显示
    service-url:
      defaultZone: http://localhost:9001/eureka,http://localhost:9002/eureka

3.2 启动类-FeignConsumerApplication

package com.asiainfo.resumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages="com.asiainfo.resumer.service")
public class FeignConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignConsumerApplication.class, args);
    }
}

RestContoller控制层-UserConsumerController

package com.asiainfo.resumer.controller;
import java.util.List;
import com.asiainfo.resumer.User;
import com.asiainfo.resumer.service.ConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
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;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserConsumerController {
    /**
     * test method
     * <p>Title: getTest</p>  
     * <p>Description: </p>  
     * @param id
     * @return
     */
    @RequestMapping(value="/consumer/gettest/{id}")
    public User getTest(@PathVariable("id") int id){
        User user = service.gettest(id);
        return user;
    }
}

Fegin消费服务接口-ConsumerService

package com.asiainfo.resumer.service;
import java.util.List;
import com.asiainfo.resumer.User;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/*以后调用resumer-user微服务中的方法,只需要调用下面对应的接口既可以了*/
@FeignClient(value="resumer-user")
public interface ConsumerService {
    /*test*/
    @RequestMapping(value="/gettest/{id}", method=RequestMethod.GET)
    public User gettest(@PathVariable("id") int id);
}

4 运行效果
Spring Cloud + Feign实现微服务负载路由
Spring Cloud + Feign实现微服务负载路由
Spring Cloud + Feign实现微服务负载路由
Spring Cloud + Feign实现微服务负载路由
Spring Cloud + Feign实现微服务负载路由前台通过访问Fegin地址 http://192.168.0.104:7001/consumer/gettest/1, 刷新10次,
resumer-feign 节点 console控制台:
2021-06-01 13:11:57.467 INFO 12876 — [nio-7001-exec-1] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client resumer-user initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=resumer-user,current list of Servers=[LAPTOP-R78VLQ0F:8003, LAPTOP-R78VLQ0F:8002],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:LAPTOP-R78VLQ0F:8002; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
, [Server:LAPTOP-R78VLQ0F:8003; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@26ada976

微服务(提供服务)节点两个【resumer-user、resumer-user2forTest】 console控制台:分别响应的次数记录:
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]

enter user2 for test web…
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]
enter user2 for test web…
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]
enter user2 for test web…
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]
enter user2 for test web…
microservice-provider微服务在响应客户端请求……
user : User [id=1, name=CJ, age=30]

上一篇:Spring Cloud实战小贴士:Feign的继承特性(伪RPC模式)


下一篇:19.下单服务(Feign远程调用、异步丢失请求头,幂等性)