Spring Cloud Alibaba系列之-OpenFeign访问远程服务(四)

一、实现目标

module[user-service]和modul[order-service]由RestTemplate通信改成用OpenFeign通信

OpenFeign官网使用文档

二、Spring Cloud OpenFeign简介

Spring Cloud OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。

三、项目[ac-mall-cloud]接入OpenFeign

3.1 父级工程配置

在父级工程 [ac-mall-cloud] pom.xml中引入OpenFeign依赖

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
     <version>${alibaba.cloud.version}</version>
</dependency>

父级工程 [ac-mall-cloud] pom.xml全配置如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ac-mall-cloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>user-service</module>
        <module>product-service</module>
        <module>order-service</module>
    </modules>

    <packaging>pom</packaging>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
        <mysql.version>8.0.17</mysql.version>
        <mybatis.plus.version>3.2.0</mybatis.plus.version>
        <druid.version>1.1.10</druid.version>
        <boot.version>2.2.4.RELEASE</boot.version>
        <alibaba.cloud.version>2.1.0.RELEASE</alibaba.cloud.version>
        <lombok.version>1.18.10</lombok.version>
    </properties>

    <!-- 管理子类所有的jar包的版本,这样的目的是方便去统一升级和维护 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>

            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis.plus.version}</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.version}</version>
            </dependency>

            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <scope>provided</scope>
            </dependency>

        </dependencies>

    </dependencyManagement>

    <!-- 所有的子工程都会自动加入下面的依赖  -->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <!-- SpringBoot 工程编译打包的插件,放在父pom中就直接给所有子工程继承 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
3.2 module [user-service] 配置

1、新建一个constant包放常量类,并新建ModulePrePath类

public class ModulePrePath {
    public static final String API = "api";
}

2、新建一个api包,放供其他微服务调用接口的类,并新建UserApi类

/**
 * @author Alan Chen
 * @description 用户API
 * @date 2021/3/31
 */
@RestController
@RequestMapping(ModulePrePath.API+"/users")
public class UserApi {

    @Autowired
    IUserService userService;

    @GetMapping("/{userId}")
    public User getUser(@PathVariable String userId){
        return userService.getUser(userId);
    }
}

module [user-service] 效果如下


module [user-service] 效果

3、测试UserApi接口
重启module [user-service] ,在浏览器中输入访问地址http://127.0.0.1:8010/api/users/1,效果如下

UserApi接口访问效果

4、api包和controller包说明
controller包里放的是供本项目前端客户端(如APP)访问的接口;api包里的接口,是专门提供给其他微服务访问的。

3.3 module [order-service] 配置

1、在module [order-service]pom.xml中引入OpenFeign依赖

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

module [order-service]pom.xml全配置如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ac-mall-cloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.ac</groupId>
    <artifactId>order-service</artifactId>

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

    </dependencies>

</project>

2、主启动类加上注解@EnableFeignClients注解
@EnableFeignClients 申明该项目是Feign客户端,扫描对应的feign client

@EnableFeignClients
@SpringBootApplication
public class OrderApplication {

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

    @Bean
    @LoadBalanced // Ribbon负载均衡注解
    RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

3、新建一个constant包放常量类,并新建ModulePrePath类

public class ModulePrePath {
    public static final String API = "api";
}

4、新建一个feign包放feign接口,并新建UserServiceClient接口

@FeignClient("user-service")
public interface UserServiceClient {

    /**
     * 获取用户信息
     * @param userId
     * @return
     */
    @GetMapping(ModulePrePath.API+"/users/{userId}")
    UserDto getUser(@PathVariable("userId") String userId);
}

@FeignClient("user-service") 配置的是module[user-service]的服务名
@GetMapping(ModulePrePath.API+"/users/{userId}") 路径和module[user-service]中UserApi获取用户信息接口的路径是一致的。

5、将RestTemplate通信改成用OpenFeign通信
修改OrderServiceImpl类的makeOrder方法

        // 1、根据用户ID调用用户服务接口数据,查询用户的名字
        //UserDto userDto = restTemplate.getForObject(USER_SERVICE_URL,UserDto.class,userId);

        //换成OpenFeign
        UserDto userDto = userServiceClient.getUser(userId);

OrderServiceImpl全部代码如下

@Service
public class OrderServiceImpl implements IOrderService {

    @Autowired
    OrderDao orderDao;

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    UserServiceClient userServiceClient;order-service
    //final static String USER_SERVICE_URL="http://127.0.0.1:8010/users/{userId}";

    final static String USER_SERVICE_URL="http://user-service/users/{userId}"; //用服务名来替换IP

    public Order makeOrder(String productId, String userId) {

        /**
         * RestTemplate是java创造出来的,在java能够访问到网络资源的包是java.net.URLConnenction/Socket
         * RestTemplate是对URLConnenction的封装
         * apache--HttpClient 也是对URLConnenction/HttpURLConnenction的封装
         * oKHttp 也封装了URLConnenction
         * netty/rpc/grpc/thirt/tomcat
         */

        // 1、根据用户ID调用用户服务接口数据,查询用户的名字
        //UserDto userDto = restTemplate.getForObject(USER_SERVICE_URL,UserDto.class,userId);

        //换成OpenFeign
        UserDto userDto = userServiceClient.getUser(userId);

        String userName=userDto.getUserName();

        // 2、生成订单
        Order order = new Order();
        order.setId(UUID.randomUUID().toString());
        order.setCreateTime(new Date());
        order.setPriceFen(1600L);
        order.setUserId(userId);
        order.setUserName(userName);
        order.setProductId(productId);
        order.setOrderNo(UUID.randomUUID().toString());

        // 3、保存数据库
        orderDao.insert(order);

        return order;
    }
}

6、测试下单接口
我们在浏览器中输入访问地址http://127.0.0.1:8020/orders/1/1,效果如下

OpenFeign成功效果图

四、Ribbon、Feign、LoadBalancer和OpenFeign的关系

4.1 Ribbon
  • Ribbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件
  • Ribbon 可以用来做客户端负载均衡,调用注册中心的服务
  • Ribbon的使用需要代码里手动调用目标服务
  • RestTemplate集成 Ribbon,可以让RestTemplate通过服务名来访问微服务接口(否则只能通过IP访问)
4.2 Feign
  • Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端
  • Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。
  • Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
  • Feign本身不支持Spring MVC的注解,它有一套自己的注解。
4.3 OpenFeign
  • OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。
  • OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
4.4 LoadBalancer

Ribbon目前已经停止维护,新版SpringCloud(2021.x.x)用LoadBalancer替代了Ribbon。Spring Cloud全家桶在Spring Cloud Commons项目中,添加了Spring cloud Loadbalancer作为新的负载均衡器,并且做了兼容

Nacos 2021版本已经没有自带ribbon的整合,所以无法通过修改Ribbon负载均衡的模式来实现nacos提供的负载均衡模式,需要引入另一个支持的jar包loadbalancer。

4.5 Ribbon/LoadBalancer载均衡策略

Ribbon有多种负载均衡策略

  • 随机 RandomRule
  • 轮询 RoundRobinRule
  • 重试 RetryRule
  • 最低并发 BestAvailableRule
  • 可用过滤 AvailabilityFilteringRule
  • 响应时间加权重 ResponseTimeWeightedRule
  • 区域权重 ZoneAvoidanceRule

LoadBalancer貌似只提供了两种负载均衡器,不指定的时候默认用的是轮询

  • RandomLoadBalancer 随机
  • RoundRobinLoadBalancer 轮询

五、附录

项目源码地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容