首页 > 其他分享 >Spring Cloud: openFegin使用

Spring Cloud: openFegin使用

时间:2024-03-26 20:33:47浏览次数:33  
标签:FeignClient openFegin String default Spring import public Cloud 客户端

文章目录

一、OpenFeign简介

OpenFeign 利用 Ribbon 维护了远程服务的列表信息,以实现客户端侧的负载均衡。

二、Springboot集成OpenFeign

1、引入依赖

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

2、@EnableFeignClients注解

(1)应用

在使用openfegin时需要再启动类上加上改注解,以启用 OpenFeign。

@SpringBootApplication
@EnableFeignClients
public class Application {

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

(2)属性解析

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
	String[] value() default {};
	
	String[] basePackages() default {};
	
	Class<?>[] basePackageClasses() default {};
	
	Class<?>[] defaultConfiguration() default {};
	
	Class<?>[] clients() default {};
}

  • basePackages 或 value
    这两个属性是等价的,用于指定扫描 Feign 客户端接口的包路径。Spring Cloud 会自动扫描这些包下的接口,并为它们创建代理实现,这些代理会实现声明的 Feign 客户端接口。
@EnableFeignClients(basePackages = "com.example.demo.client")

@EnableFeignClients(value = "com.example.demo.client")
  • defaultConfiguration
    这个属性允许你指定一个默认的配置类,该类会应用于所有 Feign 客户端,除非它们有自己特定的配置。
@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)
  • clients
    这个属性允许你明确地指定哪些接口应该作为 Feign 客户端来创建。这在你不想扫描整个包,而只想为特定的接口创建 Feign 客户端时非常有用。
@EnableFeignClients(clients = {MyServiceClient.class, AnotherServiceClient.class})
  • basePackageClasses
    @EnableFeignClients 注解中的 basePackageClasses 属性是一个替代 basePackages 或 value 的方式,用于指定扫描 Feign 客户端接口的基准类。Spring Cloud 会扫描这些基准类所在的包及其子包,以查找标有 @FeignClient 注解的接口,并为这些接口创建代理实现。

使用 basePackageClasses 而不是直接指定包路径的好处是,它提供了类型安全的方式来定义扫描的包。你只需提供一个位于所需包中的类的 Class 对象,Spring Cloud 就会自动确定该类的包路径,并扫描该包及其子包。

下面是一个使用 basePackageClasses 的例子:

@SpringBootApplication  
@EnableFeignClients(basePackageClasses = MyFeignClient.class)  
public class DemoApplication {  
  
    public static void main(String[] args) {  
        SpringApplication.run(DemoApplication.class, args);  
    }  
  
}

在这个例子中,假设 MyFeignClient 接口位于 com.example.demo.client 包中。通过指定 MyFeignClient.class 作为 basePackageClasses 的值,Spring Cloud 将扫描 com.example.demo.client 包及其所有子包,查找带有 @FeignClient 注解的接口。

这样做的好处是,即使你的包结构发生变化(例如,重命名包),只要 MyFeignClient 接口仍然位于相同的包中,你就不需要更新 @EnableFeignClients 注解。因此,它提供了一种更灵活的方式来指定扫描的包,减少了由于包路径更改而导致的维护工作量。

需要注意的是,basePackageClasses 和 basePackages/value 是互斥的,你不应该同时指定它们。你应该选择其中一种方式来定义扫描的包。通常,如果你的应用结构较为简单,直接指定包路径可能更直接。而在更复杂的场景中,使用 basePackageClasses 可能会更加灵活和易于维护。

3、 @FeignClient

(1)应用

定义一个接口,并使用 @FeignClient 注解指定远程服务的名称。

import feign.Response;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.validation.constraints.NotBlank;
import java.util.List;
@FeignClient(name = "xxx", contextId = "FileServiceAPI", path = url)
@Validated
public interface FileServiceAPI {

    /**
     * 获取文件详情接口
     * @param code
     * @return
     */
    @GetMapping
    BizBaseResponse<FileInfoVo> getFileDetail(@NotBlank @RequestParam(name = "code") String code);

    @GetMapping("files")
    BizBaseResponse<List<FileInfoVo>> getFileDetails( @RequestParam(name = "codes") List<String> codes);

    /**
     * 文件下载接口
     * @param code
     */
    @GetMapping("/download")
    Response download(@RequestParam(name = "code") String code);

(2)属性解析

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface FeignClient {

	// name和value属性用于标注客户端名称,也可以用${propertyKey}获取配置属性
	@AliasFor("name")
	String value() default "";

	// 该类的Bean名称
	String contextId() default "";

	// name和value属性用于标注客户端名称,也可以用${propertyKey}获取配置属性
	@AliasFor("value")
	String name() default "";

	// 弃用 被qualifiers()替代。
	@Deprecated
	String qualifier() default "";

	// 模拟客户端的@Qualifiers值。如果qualifier()和qualifiers()都存在,我们将使用后者,除非qualifier()返回的数组为空或只包含空值或空白值,在这种情况下,我们将首先退回到qualifier(),如果也不存在,则使用default = contextId + "FeignClient"。
	String[] qualifiers() default {};

	// 绝对URL或可解析主机名
	String url() default "";

	// 是否应该解码404而不是抛出FeignExceptions
	boolean decode404() default false;

	// 用于模拟客户端的自定义配置类。可以包含组成客户端部分的覆盖@Bean定义,默认配置都在FeignClientsConfiguration类中,可以指定FeignClientsConfiguration类中所有的配置
	Class<?>[] configuration() default {};

	// 指定失败回调类
	Class<?> fallback() default void.class;

	// 为指定的假客户端接口定义一个fallback工厂。fallback工厂必须生成fallback类的实例,这些实例实现了由FeignClient注释的接口。
	Class<?> fallbackFactory() default void.class;

	// 所有方法级映射使用的路径前缀
	String path() default "";

	// 是否将虚拟代理标记为主bean。默认为true。
	boolean primary() default true;
}

(3)向Fegin客户端提供URL的几种方式

  • 使用@FeignClient注解的url属性
    这是最直接的方式。你可以在@FeignClient注解中直接指定URL。这样,Feign客户端就会使用这个URL来进行请求。
@FeignClient(name = "myServiceClient", url = "http://example.com/api")  
public interface MyServiceClient {  
    // 定义你的方法  
}

在上面的例子中,MyServiceClient接口将使用http://example.com/api作为请求的基础URL。没有负载均衡能力,只能定向发送。

  • 使用配置文件:
    你可以在应用的配置文件(如application.yml或application.properties)中设置Feign客户端的URL。然后,你可以通过@Value注解或者@ConfigurationProperties来注入这个URL到Feign客户端的配置中。
# application.yml  
my-service-client:  
  url: http://example.com/api
@FeignClient(name = "myServiceClient", configuration = MyServiceClientConfiguration.class)  
public interface MyServiceClient {  
    // 定义你的方法  
}  

@Configuration  
public class MyServiceClientConfiguration {  

    @Value("${my-service-client.url}")  
    private String url;  

    @Bean  
    public Request.Options options() {  
        return new Request.Options(connectTimeoutMillis(), readTimeoutMillis());  
    }  

    private int connectTimeoutMillis() {  
        return 10 * 1000;  
    }  

    private int readTimeoutMillis() {  
        return 60 * 1000;  
    }  
}

在这个例子中,MyServiceClientConfiguration类从配置文件中读取URL,并可能还配置了其他的Feign请求选项。没有负载均衡能力,只能定向发送,优先使用注解中的url。

  • 使用服务发现
    如果你的应用运行在Spring Cloud环境中,并使用了服务发现(如Eureka或Consul),那么通常不需要在Feign客户端中直接指定URL。相反,你可以通过服务名称来引用远程服务,Spring Cloud会自动解析服务名称到实际的URL。
@FeignClient(name = "my-service")  
public interface MyServiceClient {  
    // 定义你的方法  
}

在这个例子中,my-service是注册在服务发现中的服务名称。当发起请求时,Spring Cloud会查询服务发现来找到my-service的实例,并使用它们的URL进行请求。

三、openFegin应用

1、使用openfegin下载文件

(1)下载文件Controler实现

import org.springframework.core.io.FileSystemResource;  
import org.springframework.core.io.Resource;  
import org.springframework.http.HttpHeaders;  
import org.springframework.http.MediaType;  
import org.springframework.http.ResponseEntity;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RestController;  
  
import javax.servlet.http.HttpServletResponse;  
import java.io.IOException;  
import java.io.InputStream;  
import java.nio.file.Files;  
import java.nio.file.Path;  
import java.nio.file.Paths;  
  
@RestController  
public class FileDownloadController {  
  
    @GetMapping("/download")  
    public void downloadFile(HttpServletResponse response) throws IOException {  
        // 文件路径  
        String filePath = "path/to/your/file.txt";  
  
        // 创建文件路径  
        Path path = Paths.get(filePath);  
        Resource resource = new FileSystemResource(path);  
  
        // 获取文件名  
        String filename = resource.getFilename();  
  
        // 设置响应头  
        response.reset();
       	response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);  
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"");  
  
        // 读取文件内容并写入响应输出流  
        try (InputStream inputStream = Files.newInputStream(path);  
             OutputStream outputStream = response.getOutputStream()) {  
  
            byte[] buffer = new byte[1024];  
            int bytesRead;  
            while ((bytesRead = inputStream.read(buffer)) != -1) {  
                outputStream.write(buffer, 0, bytesRead);  
            }  
  
            outputStream.flush();  
        }  
    }  
}

(2)openfegin配置

import feign.Response;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.validation.constraints.NotBlank;
import java.util.List;
@FeignClient(name = "xxx", contextId = "FileServiceAPI", path = url)
@Validated
public interface FileServiceAPI {
    /**
     * 文件下载接口
     * @param code
     */
    @GetMapping("/download")
    Response download();

其中Response引用的是:feign.Response

(3)调用openfegin接口方法

 public File downFileByCode() {
        String path = PROJECT_PATH;
        Response response = fileServiceAPI.download(ossFileCode);
        mkDirs(path);
        File file = new File(path);
        if (response.status() == 200) {
            try (InputStream inputStream = response.body().asInputStream();
                 FileOutputStream outputStream = new FileOutputStream(file)) {
                // 将响应体中的字节写入目标文件
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            } catch(Exception e) {
                LOGGER.error(e.getMessage(), e);
                throw new RunTimeException(e.getMessage());
            }
        }
        return file;
    }
    
    public static String mkDirs(String filePath) {
        if (StringUtils.isBlank(filePath)) {
            throw new RuntimeException("file path is null");
        }
        if (!filePath.endsWith(File.separator)) {
            LOGGER.info("mkdir , file path is {}", filePath);
            filePath = filePath.substring(0, filePath.lastIndexOf(File.separator));
        }

        //如果目录不存在,自动创建文件夹
        File dir = new File(filePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        return dir.getAbsolutePath();
    }

标签:FeignClient,openFegin,String,default,Spring,import,public,Cloud,客户端
From: https://blog.csdn.net/yuming226/article/details/137043148

相关文章

  • SpringBoot基础24_SpringBoot的配置文件4
    一、SpringBoot配置文件类型1、SpringBoot配置文件类型和作用SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。SpringBoot默认会从Resources目......
  • java毕业设计商城平台(Springboot+mysql+jdk1.8+maven3.39)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着互联网技术的迅猛发展和电子商务的蓬勃兴起,商城平台已经成为人们日常生活中不可或缺的一部分。从服装、电子产品到食品、日用品等,几乎任何想得到的商......
  • java毕业设计体检中心信息管理系统(Springboot+mysql+jdk1.8+maven3.39)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着人们健康意识的增强和医疗保健水平的提高,体检成为现代生活中不可或缺的一部分。体检中心作为提供专业健康检查服务的机构,其信息管理效率和服务质量直......
  • java毕业设计商洛市尾矿资源管理系统(Springboot+mysql+jdk1.8+maven3.39)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:商洛市位于中国陕西省东南部,该地区矿产资源丰富,历史上矿业开采活动频繁。然而,随着矿产资源的不断开发利用,产生了大量的尾矿。尾矿如果处理不当,不仅会造成......
  • java毕业设计企业知识产权管理系统(Springboot+mysql+jdk1.8+maven3.39)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:在知识经济时代,知识产权已成为企业核心竞争力的重要标志。企业为了保护自主创新成果、维护商业利益和市场竞争力,需要对专利、商标、版权等知识产权进行有......
  • java毕业设计文体用品商城的设计与实现(Springboot+mysql+jdk1.8+maven3.39)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着互联网技术的飞速发展,电子商务已经成为人们日常生活的一部分。文体用品作为日常生活中的重要组成部分,其销售模式也正在由传统的线下门店向线上电商平......
  • java毕业设计企业售后服务管理系统(Springboot+mysql+jdk1.8+maven3.39)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:在当今的商业环境中,企业之间的竞争愈发激烈,产品与服务同质化现象普遍。因此,除了提供高质量的产品之外,优质的售后服务也成为企业获得竞争优势和市场份额的......
  • springboot整合knife4j接口文档
    1、添加knife4j依赖这里是最新版本的依赖,我也会使用这个最新版本的依赖来进行举例。knife4j官网<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-spring-boot-starter</artifactId><version>4.4.0</version></d......
  • 关于SpringBoot你需要了解这些
    文章目录写在前面官网上是这么去描述springboot以及总结springboot特点的springBoot特点spring核心流程简图Springboot常用注解springBoot自动装配原理手写如何自定义starterSpringBoot是如何启动tomcat的写在前面springBoot官网官网上是这么去描述springboot......
  • spring 的理解
    spring的理解spring是一个基础的框架,同时提高了一个Bean的容器,用来装载Bean对象spring会帮我们创建Bean对象并维护Bean对象的生命周期。在spring框架上,还有springCloud,springBoot的技术框架,都是以Spring为基石的spring有两个核心,就是IOC和AOPSpringIOC是什么?......