美文网首页
Spring Cloud Alibaba系列之-OpenFeig

Spring Cloud Alibaba系列之-OpenFeig

作者: AC编程 | 来源:发表于2021-05-12 09:33 被阅读0次

    一、实现目标

    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和OpenFeign的关系

    4.1 Ribbon
    • Ribbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件
    • Ribbon 可以用来做客户端负载均衡,调用注册中心的服务
    • Ribbon的使用需要代码里手动调用目标服务
    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注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

    五、附录

    项目源码地址

    相关文章

      网友评论

          本文标题:Spring Cloud Alibaba系列之-OpenFeig

          本文链接:https://www.haomeiwen.com/subject/kanodltx.html