项目结构
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