美文网首页微服务架构和实践
Spring全家桶——SprinCloud之Feign(Finc

Spring全家桶——SprinCloud之Feign(Finc

作者: Java_Pro | 来源:发表于2019-03-05 16:13 被阅读0次

    授权"Java知音"首发 ---Official Accounts

    Spring全家桶——SprinCloud之Feign(Finchley版)

    Feign是一个声明式的Web服务客户端。

    是什么?
    例如我在一个服务的interace上注解@FeignClient(value = "eureka-client")
    就是声明服务名称 告诉其他服务等这个就是eureka-client 的服务客户端
    它使编写Web服务客户端变得更容易

    要使用Feign,请创建接口并注解,有可插入的注解支持,包括Feign注释和JAX-RS注释。

    JAX-RS注释:JAX-RS是JAVAEE6 引入的,JAX-RS即Java API for RESTful Web Services
    是Java的应用程序接口,如:
    @Path标注资源类或方法的相对路径
    @GET,@PUT,@POST,@DELETE 请求方式

    Feign还支持可插拔编码器和解码器。

    Spring Cloud Netflix 为 Feign提供了下面默认的配置Bean
    Decoder feignDecoder: ResponseEntityDecoder
    Encoder feignEncoder: SpringEncoder
    Spring Cloud增加了对Spring MVC注释的支持
    并使用了Spring Web中默认使用的相同HttpMessageConverters。

    Spring Cloud集成了Ribbon和Eureka,在使用Feign时提供负载均衡的http客户端。

    白话文:微服务架构端口很多,我们要统一端口就要用到Feign去各个服务拿接口;需要从一个服务调用另外一个服务的数据也可以直接使用Feign,也就是通过这种方式开发调用远程服务就像是调用本地服务一样方便。

    准备工作

    • 环境
    1. IDEA 2018.3
    2. Gradle 4.10
    3. springCloudVersion Finchley.RELEASE
    4. 无eureka-server的可以去github下载源码:https://github.com/cuifuan/springcloud-tools
    5. 创建的是子项目,父项目Github下载

    创建eureka-client服务

    gradle配置 build.gradle

    dependencies {
        implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation project(":tools-common-entity")
    }
    

    创建启动类 ToolsEurekaClientApplication.java

    package store.zabbix.toolseurekaclient;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @EnableEurekaClient
    @RestController
    public class ToolsEurekaClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ToolsEurekaClientApplication.class, args);
        }
    
        @Value("${server.port}")
        private int port;
    
        @GetMapping("test")
        public String showPort(@RequestParam(value = "name",required = false) String name){
            if (name == null)
                name = "Anonymous";
            return "my port is "+port +" -> my name is"+name;
        }
    
    }
    

    资源文件 application.yml

    eureka:
      client:
        service-url:
          defaultZone: http://127.0.0.1:8761/eureka/
    server:
      port: 8762
    spring:
      application:
        name: eureka-client
    

    业务接口 UserService.java

    package store.zabbix.toolseurekaclient.service;
    
    
    import store.zabbix.common.entity.User;
    
    import java.util.List;
    
    public interface UserService {
    
        Integer createUser(User user);
    
        List<User> getUserAll(String username,Long id);
    
        Integer updateUser(User user);
    
        Integer deleteUser(List<Integer> ids);
    
    }
    
    

    业务实现层 UserServiceImpl.java

    package store.zabbix.toolseurekaclient.service.impl;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Service;
    import store.zabbix.common.entity.User;
    import store.zabbix.toolseurekaclient.service.UserService;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    @Service
    @Slf4j
    public class UserServiceImpl implements UserService {
        @Override
        public Integer createUser(User user) {
            log.info("创建数据:{}",user.toString());
            return 1;
        }
    
        @Override
        public List<User> getUserAll(String username,Long id) {
            log.info("查询全部->参数1:{}->参数2:{}",username,id);
            User user=new User(1L,"admin","123456");
            return new ArrayList<User>(){{add(user);}};
        }
    
        @Override
        public Integer updateUser(User user) {
            log.info("更新数据..{}",user.toString());
            return 1;
        }
    
        @Override
        public Integer deleteUser(List<Integer> ids) {
            log.info("删除用户ids->{}",ids.toString());
            return 1;
        }
    }
    
    

    控制层 UserController.java

    package store.zabbix.toolseurekaclient.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import store.zabbix.common.entity.User;
    import store.zabbix.toolseurekaclient.service.UserService;
    
    import java.util.List;
    
    @RestController
    @RequestMapping("user")
    public class UserController {
    
        private final UserService userService;
    
        @Autowired
        public UserController(UserService userService) {
            this.userService = userService;
        }
    
        @GetMapping
        public List<User> getUserList(String username,Long id){
            return userService.getUserAll(username,id);
        }
    
        @PostMapping
        public Integer createUser(@RequestBody User user){
            return userService.createUser(user);
        }
    
        @PutMapping
        public Integer updateUser(@RequestBody User user){
            return userService.updateUser(user);
        }
    
        @DeleteMapping
        public Integer deleteUSer(@RequestBody List<Integer> idList){
            return userService.deleteUser(idList);
        }
    }
    
    

    由上面的server.port 可知端口为8762
    可是如果我们有多个eureka-client怎么办
    会造成后端接口访问端口太多
    所以在这里可以采用feign进行统一调度

    新建tools-routing服务

    build.gradle

    dependencies {
        implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
        implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
        implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
    }
    

    新建的是子项目,依赖管理统一在父项目,子项目只声明自己单独使用的依赖,父项目在github可以进行拉取,地址在上面

    启动类 ToolsRoutingApplication.java

    package store.zabbix.toolsrouting;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    public class ToolsRoutingApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ToolsRoutingApplication.class, args);
        }
    
    }
    
    

    核心就是开启@EnableFeignClients注解

    application.yml

    server:
      port: 8765
    eureka:
      client:
        service-url:
          defaultZone: http://127.0.0.1:8761/eureka/
    spring:
      application:
        name: service-feign
    

    创建UserServiceClients调用eureka-client接口

    package store.zabbix.toolsrouting.service;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import store.zabbix.common.entity.User;
    
    import java.util.List;
    
    @FeignClient("eureka-client")
    public interface UserServiceClients {
        @GetMapping
        List<User> getUserList(String name,Long id);
    }
    
    

    @FeignClient是核心,@FeignClient里value的值是eureka-client的application.yml声明的,如下:

    spring:
      application:
        name: eureka-client
    

    启动ToolsRoutingApplication.java
    发现启动报错

    image

    说明:
    @GetMapping在这个版本可以使用,其传值要使用@RequestParam
    在一些版本无法使用@GetMapping,需使用@RequestMapping(value = "user",method = RequestMethod.GET)

    UserServiceClients接口

    package store.zabbix.toolsrouting.service;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.*;
    import store.zabbix.common.entity.User;
    
    import java.util.List;
    
    @FeignClient("eureka-client")
    public interface UserServiceClients {
        @GetMapping("user")
    //@RequestMapping(value = "user",method = RequestMethod.GET)
        List<User> getUserList(@RequestParam("username") String name,@RequestParam("id") Long id);
    //这里不加@RequestParam会报异常IllegalStateException: Method has too many Body parameters,造成无法启动
        @PostMapping("user")
        Integer createUser(@RequestBody User user);
    
        @PutMapping(value = "user",produces = "application/json")
        Integer updateUser(@RequestBody User user);
    
        @DeleteMapping(value = "user",produces = "application/json")
        Integer deleteUser(@RequestBody List<Integer> ids);
    }
    
    
    

    说明:PUT和DELETE请求,使用json传输List<Object>时或许会报错,请在注解内加上参数produces = "application/json",如@DeleteMapping(value = "user",produces = "application/json")

    创建 UserController.java 控制访问层
    package store.zabbix.toolsrouting.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import store.zabbix.common.entity.User;
    import store.zabbix.common.entity.bean.ResultBean;
    import store.zabbix.toolsrouting.service.UserServiceClients;
    
    import java.util.List;
    
    @RequestMapping("user")
    @RestController
    public class UserController {
        private final UserServiceClients userServiceClients;
    
        @Autowired
        public UserController(UserServiceClients userServiceClients) {
            this.userServiceClients = userServiceClients;
        }
    
        @GetMapping
        public ResultBean<List<User>> getUserList(String name, Long id) {
            return new ResultBean<>(userServiceClients.getUserList(name, id));
        }
    
        @PostMapping
        public ResultBean<Integer> createUser(@RequestBody User user) {
            return new ResultBean<>(userServiceClients.createUser(user));
        }
    
        @PutMapping
        public ResultBean<Integer> updateUser(@RequestBody User user){
            return new ResultBean<>(userServiceClients.updateUser(user));
        }
    
        @DeleteMapping
        public ResultBean<Integer> deleteUser(@RequestBody List<Integer> integerList){
            return new ResultBean<>(userServiceClients.deleteUser(integerList));
        }
    }
    
    

    Postman 测试结果

    查询
    image
    添加
    image
    修改
    image
    删除
    image

    有postman的可以使用下面的链接:
    https://www.getpostman.com/collections/8f56e7246e290e8036f0

    SpringCloud各版本出现的问题坑等很多,遇到问题尽量自行解决,收获才会有很多

    福利

    下面送给大家自网络收集的图书(侵删):

    image image

    链接:https://www.lanzous.com/i8pi9je

    相关文章

      网友评论

        本文标题:Spring全家桶——SprinCloud之Feign(Finc

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