自己简单实现 feign-reactive的基本功能

1 篇文章 0 订阅
1 篇文章 0 订阅

项目结构

  • myfeign-reactive
    • myfeign-reactive-spring-boot-starter
    • myfeign-reactive-spring-boot-autoconfigure
    • test-consumer
    • test-provider
    • test-common

依赖:

<dependency>
	<groupId>com.my.framework</groupId>
	<artifactId>myfeign-reactive-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

myfeign-reactive-spring-boot-autoconfigure中核心部分代码如下:
EnableFeignClient

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(FeignImportBeanDefinitionRegistrar.class)
public @interface EnableFeignClient {
}

FeignClient

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
   String serverName();
   String serverUrl();
}

FeignImportBeanDefinitionRegistrar : 为FeignClient标注的接口生成代理类并注册进容器

public class FeignImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
   @Override
   public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

       // 获取 @EnableFeignClient 标注的位置,作为基础包
       String enableFeignClientPackage = ((StandardAnnotationMetadata) importingClassMetadata).getIntrospectedClass().getPackage().getName();
       // 获取基础包下所有的标注@FeignClient注解的接口
       Set<Class<?>> FeignClientAnnotationClasses = ClassScanner.scan(enableFeignClientPackage, FeignClient.class);

       // 为这些接口生成代理类并注册进容器
       for (Class<?> feignClientAnnotationClass : FeignClientAnnotationClasses) {
           GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
           beanDefinition.setBeanClassName(FeignClientFactoryBean.class.getName());

           ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
           constructorArgumentValues.addGenericArgumentValue(feignClientAnnotationClass);
           beanDefinition.setConstructorArgumentValues(constructorArgumentValues);

           registry.registerBeanDefinition(feignClientAnnotationClass.getSimpleName(), beanDefinition);
       }
   }
}

FeignClientFactoryBean :为FeignClient标注的接口生成代理类

public class FeignClientFactoryBean<T> implements FactoryBean<T> {

   Class<T> clazz;

   public FeignClientFactoryBean(Class<T> clazz) {
       this.clazz = clazz;
   }

   @Override
   public T getObject() {
       return (T) Proxy.newProxyInstance(getObjectType().getClassLoader(), new Class[]{getObjectType()}, (proxy, method, args) -> {
           InterfaceInfo interfaceInfo = ExtractInfoUtil.extractInterfaceInfo(clazz);
           MethodInfo methodInfo = ExtractInfoUtil.extractMethodInfo(method, args);
           return WebClientUtil.request(interfaceInfo, methodInfo);
       });
   }

   @Override
   public Class<T> getObjectType() {
       return clazz;
   }

   @Override
   public boolean isSingleton() {
       return true;
   }
}

ExtractInfoUtil : 解析出后面WebClient需要的参数

public class ExtractInfoUtil {

   public static InterfaceInfo extractInterfaceInfo(Class<?> clazz) {
       InterfaceInfo interfaceInfo = new InterfaceInfo();

       for (Annotation annotation : clazz.getAnnotations()) {
           if (annotation instanceof FeignClient) {
               FeignClient feignClientAnnotation = (FeignClient) annotation;
               interfaceInfo.setServerName(feignClientAnnotation.serverName());
               interfaceInfo.setServerUrl(feignClientAnnotation.serverUrl());
           }
           if (annotation instanceof RequestMapping) {
               RequestMapping requestMappingAnnotation = (RequestMapping) annotation;
               interfaceInfo.setClassUri(requestMappingAnnotation.value()[0]);
           }
       }

       return interfaceInfo;
   }
   
   public static MethodInfo extractMethodInfo(Method method, Object[] args) {
       MethodInfo methodInfo = new MethodInfo();
       Map<String, Object> pathVariables = new HashMap<>();

       for (Annotation annotation : method.getAnnotations()) {
           if (annotation instanceof GetMapping) {
               methodInfo.setUri(((GetMapping) annotation).value()[0]);
               methodInfo.setHttpMethod(HttpMethod.GET);
           } else if (annotation instanceof PostMapping) {
               methodInfo.setUri(((PostMapping) annotation).value()[0]);
               methodInfo.setHttpMethod(HttpMethod.POST);
           } else if (annotation instanceof DeleteMapping) {
               methodInfo.setUri(((DeleteMapping) annotation).value()[0]);
               methodInfo.setHttpMethod(HttpMethod.DELETE);
           } else if (annotation instanceof PutMapping) {
               methodInfo.setUri(((PutMapping) annotation).value()[0]);
               methodInfo.setHttpMethod(HttpMethod.PUT);
           }
       }

       Annotation[][] parameterAnnotations = method.getParameterAnnotations();
       for (int i = 0; i < parameterAnnotations.length; i++) {
           for (Annotation annotation : parameterAnnotations[i]) {
               if (annotation instanceof PathVariable) {
                   pathVariables.put(((PathVariable) annotation).value(), args[i]);
               }
               if (annotation instanceof RequestBody) {
                   methodInfo.setRequestBodyValue(args[i]);
               }
           }
       }

       // 获取方法返回值的泛型的class信息
       Type genericReturnType = ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0]; // 获取返回值的泛型类型
       Class<?> genericReturnClass = (Class<?>) ((ParameterizedType) genericReturnType).getRawType(); // 将泛型类型转为class
       methodInfo.setResponseBodyType(genericReturnClass);

       methodInfo.setReturnMono(method.getReturnType().isAssignableFrom(Mono.class));
       methodInfo.setPathVariables(pathVariables);
       return methodInfo;
   }
}

WebClientUtil :利用WebClient非阻塞的发送请求

public class WebClientUtil {

   private static final WebClient webClient = WebClient.create();

   public static Object request(InterfaceInfo interfaceInfo, MethodInfo methodInfo) {
       // 请求
       WebClient.RequestBodySpec request = webClient.method(methodInfo.getHttpMethod())
               .uri(interfaceInfo.getServerUrl() + interfaceInfo.getClassUri() + methodInfo.getUri(), methodInfo.getPathVariables())
               .accept(MediaType.APPLICATION_JSON);

       if (methodInfo.getRequestBodyValue() != null) {
           request.bodyValue(methodInfo.getRequestBodyValue());
       }

       WebClient.ResponseSpec response = request.retrieve();

       // 解析响应
       if (methodInfo.isReturnMono()) {
           return response.bodyToMono(methodInfo.getResponseBodyType());
       } else {
           return response.bodyToFlux(methodInfo.getResponseBodyType());
       }
   }
}

测试部分的代码没有粘贴出来,详细代码参考:
源码地址:https://gitee.com/cai-qiangfei/myframework/tree/master/myfeign-reactive
clone命令: git clone http://gitee.com/cai-qiangfei/myframework.git

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`feign-spring-mvc-starter` 是一个 Feign 的扩展,它支持使用 Spring MVC 注解来定义和调用 REST 服务。使用 `feign-spring-mvc-starter`,你可以像使用 Spring MVC 控制器一样定义 Feign 客户端,从而更方便地进行 REST 服务的开发。 在使用 `feign-spring-mvc-starter` 之前,你需要先了解 FeignSpring MVC 的基本概念和用法。 Feign 是一个声明式的 Web 服务客户端,它可以帮助你更方便地定义和调用 REST 服务。Feign 的基本使用方法是定义一个接口,用于描述 REST 服务的 API,然后使用 Feign 注解来声明这个接口。 Spring MVC 是一个基于 Java 的 Web 框架,它提供了一组注解和 API,用于处理 Web 请求和响应。 `feign-spring-mvc-starter` 将 FeignSpring MVC 结合起来,使你可以使用 Spring MVC 注解来定义和调用 REST 服务。使用 `feign-spring-mvc-starter`,你可以更方便地使用 Feign 来调用 REST 服务。 以下是一个使用 `feign-spring-mvc-starter` 的示例: 1. 添加 Maven 依赖 在 pom.xml 文件中添加以下依赖项: ```xml <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-spring-mvc</artifactId> <version>5.3.1</version> </dependency> ``` 2. 定义 Feign 接口 定义一个 Feign 接口,用于描述 REST 服务的 API。例如: ```java @FeignClient(name = "example-service") public interface ExampleClient { @GetMapping("/example") String getExample(); } ``` 在这个接口中,我们使用了 `@FeignClient` 注解来声明这个接口是一个 Feign 客户端,并指定了服务的名称。然后,我们定义了一个 `getExample()` 方法,用于调用 example-service 服务的 /example 路径。 3. 定义 Spring MVC 控制器 定义一个 Spring MVC 控制器,用于处理来自客户端的请求。例如: ```java @RestController public class ExampleController { private final ExampleClient exampleClient; public ExampleController(ExampleClient exampleClient) { this.exampleClient = exampleClient; } @GetMapping("/") public String index() { return exampleClient.getExample(); } } ``` 在这个控制器中,我们注入了 `ExampleClient`,并在 `index()` 方法中使用它来调用 example-service 服务的 /example 路径。 4. 运行应用程序 现在,你可以运行应用程序并访问 http://localhost:8080/ ,你应该会看到来自 example-service 服务的响应。 这就是一个使用 `feign-spring-mvc-starter` 的示例。使用 `feign-spring-mvc-starter`,你可以更方便地使用 Feign 来调用 REST 服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值