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

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Spring全家桶—SpringCloud之Feign(Finchley版)

点击上方“Java知音”,选择“置顶公众号”

技术文章第一时间送达!

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,也就是通过这种方式开发调用远程服务就像是调用本地服务一样方便。

    准备工作

  • 环境
  • IDEA 2018.3
  • Gradle 4.10
  • springCloudVersion Finchley.RELEASE
  • 没有eureka-server的可以去github下载源码: https://github.com/cuifuan/springcloud-tools
  • 创建的是子项目,父项目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);
    
        ListUser getUserAll(String username,Long id);
    
        Integer updateUser(User user);
    
        Integer deleteUser(ListInteger 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 ListUser getUserAll(String username,Long id) {
            log.info("查询全部-参数1:{}-参数2:{}",username,id);
            User user=new User(1L,"admin","123456");
            return new ArrayListUser(){{add(user);}};
        }
    
        @Override
        public Integer updateUser(User user) {
            log.info("更新数据..{}",user.toString());
            return 1;
        }
    
        @Override
        public Integer deleteUser(ListInteger 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 ListUser 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 ListInteger 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
        ListUser getUserList(String name,Long id);
    }
    

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

    
    spring:
      application:
        name: eureka-client
    

    启动 ToolsRoutingApplication.java 
    发现启动报错 

    说明: @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)
        ListUser 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 ListInteger ids);
    }
    

    说明:PUT和DELETE请求,使用json传输List时或许会报错,请在注解内加上参数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 ResultBeanListUser getUserList(String name, Long id) {
            return new ResultBean(userServiceClients.getUserList(name, id));
        }
    
        @PostMapping
        public ResultBeanInteger createUser(@RequestBody User user) {
            return new ResultBean(userServiceClients.createUser(user));
        }
    
        @PutMapping
        public ResultBeanInteger updateUser(@RequestBody User user){
            return new ResultBean(userServiceClients.updateUser(user));
        }
    
        @DeleteMapping
        public ResultBeanInteger deleteUser(@RequestBody ListInteger integerList){
            return new ResultBean(userServiceClients.deleteUser(integerList));
        }
    }
    

    Postman 测试结果

    查询
    添加
    修改
    删除

    有postman的可以使用下面的链接: 

    https://www.getpostman.com/collections/8f56e7246e290e8036f0

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

    福利

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

    链接:https://pan.baidu.com/s/1KmFPYhnXqxLzL4CiTEo45g 密码:kk3u

    加入Java知音技术交流,戳这里:

    更多Java技术文章,尽在【Java知音】网站。

    网址:www.javazhiyin.com  ,搜索Java知音可达!

    看完本文有收获?请转发分享给更多人

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

    原文始发于微信公众号(Java知音):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> Spring全家桶—SpringCloud之Feign(Finchley版)


     上一篇
    【加精】Spring Cloud Zuul路由动态配置 【加精】Spring Cloud Zuul路由动态配置
    Spring Cloud Zuul动态路由配置 Zuul配置 在mysql中创建路由信息表,对于类如下: 定义CustomRouteLocator类 增加CustomZuulConfig类,主要是为了配置CustomRouteLocator
    下一篇 
    SpringCloud Alibaba-nacos注册中心 SpringCloud Alibaba-nacos注册中心
    点击上方“Java知音”,选择“置顶公众号” 技术文章第一时间送达! 本文系投稿,作者:小毛毛cnblogs.com/zgwjava/p/10562775.html cnblogs.com/zgw