微服务技术--------Feign远程调用

一、使用场景:在本人第一次接触微服务项目时,感觉真的很高大上,我们的项目是根据功能来划分的模块,一个父工程下有很多子模块(子工程)。
有一次我在system模块想调用admin模块里面的一个接口方法时,我直接在system模块的impl下使用

    @Autowired
    @Lazy
    private SysAdminCompanyService companyService;

直接引入了admin模块里面的方法,这样,在system的pom文件中就新增了admin模块的依赖,后来有同事告诉我不能这样用。既然是微服务开发,分模块做,再这样引入不同块的依赖,就失去了解耦合的意义。因此这里就用到了feign远程调用的技术:

请看项目的工程图解:
在这里插入图片描述二、了解feign:
Feign是一个声明式WebService客户端。
在SpringCloud用于实现微服务之间的互相调用。
服务消费者无需知道服务提供者的ip和端口,只需要 指定服务名,即可通过注册中心调用到目标服务。
{所以这里从字面意思上讲,就是不同服务之间的调用,只需要指定服务名就可以调到了}
下面我们来实战下如何实现服务间的接口调用:
三、实战操作
步骤:1、创建两个微服务的模块,一个作为提供者,一个作为消费者
2、导入feign依赖,在启动类中开启feign
3、在application.yml中配置feign
4、利用feignclient调用远程接口
这里首先创建注册中心的模块:
eureka
pom.xml

        <!---->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
       <!--注册中的依赖-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>

application.yml:

#配置注册中心1的端口,可以随意设置,不能跟其他端口冲突
server:
  port: 10010
#配置注册中心1的名字,可以随意起
spring:
  application:
    #通过查看注册中心查看有哪些模块注册进了这个注册中心
    name: EurekaServer1
eureka:
  client:
    service-url:
    #配置访问路径
      defaultZone: http://127.0.0.1:10010/eureka
      #允许注册中心注册自己,分布式web模块、网关、
      #包括注册中心自己也都要注册(到注册中心)进来,如果注册中心多可以相互注册
      #register-with-eureka: true

eurekaStart:启动类

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

/**
 * 注册中心启动类
 */


@SpringBootApplication
@EnableEurekaServer//开启注册中心的职务
public class EurekaStart1 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaStart1.class);
    }
}

admin模块:提供者模块
pom.xml

        <!--Eureka客户端-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
        

application.yml

#配置后台admin的端口号
server:
  port: 8999
#给后台admin模块设置名字
spring:
  application:
    name: hbuy-admin
#将后台模块注册到注册中心
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10010/eureka      

adminStart启动类:

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * admin模块的启动类
 */
@EnableEurekaClient
@SpringBootApplication(scanBasePackages = "com.java.admin")
@MapperScan(basePackages = "com.java.admin.mapper")
public class AdminStart {



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

提供者接口类

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName: LoginController
 * @Description:
 * @Version: v1.0.0
 * @Author: Fu
 * @Date: 2019/12/19 0019 下午 3:54
 * Modification History:
 * Date           Author      Version     Description
 * -------------------------------------------------------------
 * 2019/12/19 0019        Fu      v1.0.0         创建
 */
@RestController
@RequestMapping("/admin")
public class LoginController {

    @GetMapping("/user")
    public String getUser(String age) {
        System.out.println("小明"+age);
        return "xiaoming";
    }
}

消费者模块:
CustomController:

<!---->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
        <!--Eureka客户端-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
        <!--feign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>

application.yml:

#配置后台admin的端口号
server:
  port: 8100

#给后台admin模块设置名字
spring:
  application:
    name: hbuy-autosell
#将后台模块注册到注册中心
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10010/eureka

启动类Custome:

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

/**
 * @ClassName: CustomStart
 * @Description:
 * @Version: v1.0.0
 * @Author: Fu Hao
 * @Date: 2019/12/19 0019 下午 4:27
 * Modification History:
 * Date           Author      Version     Description
 * -------------------------------------------------------------
 * 2019/12/19 0019        Fu      v1.0.0         创建
 */
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class CustomStart {

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

feign远程调用接口:

import com.joyoung.cloud.fallback.LoginFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @ClassName: LoginService
 * @Description:
 * @Version: v1.0.0
 * @Author: Fu Hao
 * @Date: 2019/12/19 0019 下午 4:52
 * Modification History:
 * Date           Author      Version     Description
 * -------------------------------------------------------------
 * 2019/12/19 0019        Fu      v1.0.0         创建
 */
@FeignClient(value = "hbuy-admin",fallback = LoginFallBack.class)
public interface LoginService {

    @GetMapping("/user")
    public String getUser(@RequestParam("age") String age);
}

fallback远程调用接口实现类打印日志信息:

import com.joyoung.cloud.feign.LoginService;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @ClassName: LoginFallBack
 * @Description:
 * @Version: v1.0.0
 * @Author: Fu Hao
 * @Date: 2019/12/19 0019 下午 4:49
 * Modification History:
 * Date           Author      Version     Description
 * -------------------------------------------------------------
 * 2019/12/19 0019        Fu      v1.0.0         创建
 */
@Slf4j
@Service
public class LoginFallBack implements LoginService {
    @Override
    public String  getUser(@RequestParam("age") String age) {
        log.error("调用{}异常{}", "age", age);
        return null;
    }
}

调用接口:

import com.joyoung.cloud.feign.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName: AutoSellController
 * @Description:
 * @Version: v1.0.0
 * @Author: Fu Hao
 * @Date: 2019/12/19 0019 下午 4:41
 * Modification History:
 * Date           Author      Version     Description
 * -------------------------------------------------------------
 * 2019/12/19 0019        Fu      v1.0.0         创建
 */

@RestController
@RequestMapping("com")
public class AutoSellController {

    @Autowired
    private LoginService service;


    public String test(){
        String age="12";
        return service.getUser(age);
    }
    
}

本文引荐了这篇文章:http://markey.cc/2018/12/09/SpringCloud%E5%85%A5%E9%97%A8%E4%B9%8B%E5%9F%BA%E4%BA%8EFeign%E7%9A%84%E6%9C%8D%E5%8A%A1%E9%97%B4%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8/

下面截几段代码展示我们项目中的远程调用:

调用接口:

import com.joyoung.cloud.moudles.system.Fallback.SysAdminUserServiceBack;
import com.joyoung.cloud.security.common.config.FeignConfig;
import com.joyoung.cloud.security.common.entity.admin.SysUser;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
/**
 * @ClassName: IAdminService
 * @Description:
 * @Version: v1.0.0
 * @Author: Fu Hao
 * @Date: 2019/11/11 0011 下午 2:47
 * Modification History:
 * Date           Author      Version     Description
 * -------------------------------------------------------------
 * 2019/11/11 0011        Fu      v1.0.0         创建
 */
@FeignClient(value = "cloud-admin",fallback = SysAdminUserServiceBack.class,configuration = {FeignConfig.class})
public interface  SysAdminUserService{
    /**
     * @return void
     * @Description 修改用户信息
     * @Date 2019/6/18
     * @Param [entity, coIds]
     **/
    @PutMapping("/userAdmin")
    public Object edit(SysUser user);
    /***
     * @Description  添加用户信息
     * @author Fu Hao on 2019/11/13 0013 下午 2:05
     * @return
     **/
    @PostMapping("/userAdmin")
    public Object add(SysUser user);
    /***
     * @Description 删除一条用户
     * @author Fu Hao on 2019/11/13 0013 下午 2:08
     * @return
     **/
    @DeleteMapping(value = "/userAdmin/{id}")
    public Object del(@PathVariable(value = "id") String id);
}

FeignConfig配置信息:

import com.joyoung.cloud.security.common.context.BaseContextHandler;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

@Component
public class FeignConfig implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            String token = request.getHeader(HttpHeaders.AUTHORIZATION);
            BaseContextHandler.setToken(token);
        }
    }

    @Bean
    Logger.Level feignLevel() {
        return Logger.Level.FULL;
    }

}

实现类:

import com.joyoung.cloud.moudles.system.feign.SysAdminUserService;
import com.joyoung.cloud.security.common.entity.admin.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @ClassName: IAdminBack
 * @Description:
 * @Version: v1.0.0
 * @Author: Fu Hao
 * @Date: 2019/11/12 0012 下午 3:46
 * Modification History:
 * Date           Author      Version     Description
 * -------------------------------------------------------------
 * 2019/11/12 0012        Fu      v1.0.0         创建
 */

@Service
@Slf4j
public class SysAdminUserServiceBack implements SysAdminUserService {



    @Override
    public Object edit(SysUser sysUser) {
        log.error("调用{}异常{}", "sysUser", sysUser);
        return null;
    }

    @Override
    public Object add(SysUser user) {
        log.error("调用{}异常","user");
        return null;
    }

    @Override
    public Object del(@RequestParam("id") String id) {
        log.error("调用{}异常{}","id",id);
        return null;
    }
}

提供方法的接口:

import com.github.pagehelper.PageInfo;
import com.joyoung.cloud.moudles.admin.service.SysAdminUserService;
import com.joyoung.cloud.security.common.entity.admin.SysCompany;
import com.joyoung.cloud.security.common.entity.admin.SysUser;
import com.joyoung.cloud.security.common.msg.RestRes;
import com.joyoung.cloud.security.common.validatedGroup.Add;
import com.joyoung.cloud.security.common.validatedGroup.Modify;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;

/**
 * @ClassName: SysAdminUserController
 * @Description: 用户管理
 * @Version: v1.0.0
 * @Author: yan
 * @Date: 2019-05-15 14:47
 * Modification History:
 * Date             Author      Version     Description
 * -------------------------------------------------------------
 * 2019-08-15      t      v1.0.0      创建
 */
@Api(tags = "平台用户接口")
@RestController
@RequestMapping("/userAdmin")
public class SysAdminUserController {

    @Autowired
    private SysAdminUserService service;

    /**
     * @param user description
     * @return java.lang.Object
     * @Description 添加一条记录 同时绑定公司与角色
     * @author tengyun on 2019-08-20 16:51
     */
    @ApiOperation(value = "添加一条记录 同时绑定公司与角色")
    @PostMapping("")
    public Object add(@Validated({Add.class}) @RequestBody SysUser user) {
        service.addOrModify(user, user.getCoIdsList());
        return 1;
    }

    /**
     * @param user description
     * @return java.lang.Object
     * @Description 编辑信息 同时绑定公司与角色
     * @author tengyun on 2019-08-20 16:51
     */
    @ApiOperation(value = "编辑信息 同时绑定公司与角色")
    @PutMapping("")
    public Object edit(@Validated({Modify.class}) @RequestBody SysUser user) {
        service.addOrModify(user, user.getCoIdsList());
        return 1;
    }

    /**
     * @param id description
     * @return java.lang.Object
     * @Description 删除信息
     * @author tengyun on 2019-08-20 16:51
     */
    @ApiOperation(value = "删除信息")
    @DeleteMapping("/{id}")
    public Object del(@PathVariable(value = "id") String id) {
        service.deleteById(id);
        return 1;
    }

    /**
     * @param id description
     * @return java.lang.Object
     * @Description 查询单个用户
     * @author tengyun on 2019-08-20 16:51
     */
    @ApiOperation(value = "查询单个用户")
    @GetMapping("/{id}")
    public Object get(@PathVariable String id) {
        return service.selectById(id);
    }


}

总结:
Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。

在Spring Cloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。

Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。

Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix
Feign 是一个声明式的伪RPC的REST客户端,它用了基于接口的注解方式,很方便的客户端配置,Spring Cloud 给 Feign 添加了支持Spring MVC注解,并整合Ribbon及Eureka进行支持负载均衡。
坑点:远程调用的时候可能不起作用,检查熔断器,将熔断器注释掉,再启动项目调用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值