Skip to content

Commit

Permalink
@RetrofitClient、@Retry等注解支持元注解、继承以及@AliasFor
Browse files Browse the repository at this point in the history
  • Loading branch information
chentianming11 committed May 7, 2022
1 parent 7c28a09 commit c1f88b8
Show file tree
Hide file tree
Showing 25 changed files with 262 additions and 54 deletions.
28 changes: 26 additions & 2 deletions README.md
Expand Up @@ -41,6 +41,7 @@ gitee项目地址:[https://gitee.com/lianjiatech/retrofit-spring-boot-starter]
- [x] [全局拦截器](#全局拦截器)
- [x] [调用适配器](#调用适配器)
- [x] [数据转换器](#数据转码器)
- [x] [元注解](#元注解)
- [x] [其他功能示例](#其他功能示例)

## 快速使用
Expand All @@ -51,7 +52,7 @@ gitee项目地址:[https://gitee.com/lianjiatech/retrofit-spring-boot-starter]
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.3.1</version>
<version>2.3.2</version>
</dependency>
```

Expand All @@ -64,7 +65,7 @@ gitee项目地址:[https://gitee.com/lianjiatech/retrofit-spring-boot-starter]
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.3.1</version>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
Expand Down Expand Up @@ -854,6 +855,29 @@ retrofit:

针对每个Java接口,还可以通过`@RetrofitClient`注解的`converterFactories()`指定当前接口采用的`Converter.Factory`,指定的转换器工厂实例依然优先从Spring容器获取。

### 元注解

`@RetrofitClient`、`@Retry`、`@Logging`、`@Resilience4jDegrade`等注解支持元注解、继承以及`@AliasFor`。 我们可以随意组合、调整相关注解:

```java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Logging(logLevel = LogLevel.WARN)
@Retry(intervalMs = 200)
public @interface MyRetrofitClient {

@AliasFor(annotation = RetrofitClient.class, attribute = "converterFactories")
Class<? extends Converter.Factory>[] converterFactories() default {GsonConverterFactory.class};

@AliasFor(annotation = Logging.class, attribute = "logStrategy")
LogStrategy logStrategy() default LogStrategy.BODY;
}
```

## 其他功能示例

### form参数接口调用
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -6,7 +6,7 @@

<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.3.1</version>
<version>2.3.2</version>

<name>retrofit-spring-boot-starter</name>
<description>retrofit-spring-boot-starter</description>
Expand Down
Expand Up @@ -10,13 +10,15 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -87,7 +89,8 @@ public boolean isSingleton() {
}

private okhttp3.ConnectionPool parseConnectionPool() {
RetrofitClient retrofitClient = retrofitInterface.getAnnotation(RetrofitClient.class);
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class);
String poolName = retrofitClient.poolName();
Map<String, ConnectionPool> poolRegistry = retrofitConfigBean.getPoolRegistry();
Assert.notNull(poolRegistry, "poolRegistry does not exist! Please set retrofitConfigBean.poolRegistry!");
Expand All @@ -99,7 +102,8 @@ private okhttp3.ConnectionPool parseConnectionPool() {

private OkHttpClient createOkHttpClient() throws IllegalAccessException, InvocationTargetException {
OkHttpClient.Builder okHttpClientBuilder = createOkHttpClientBuilder();
RetrofitClient retrofitClient = retrofitInterface.getAnnotation(RetrofitClient.class);
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class);
if (isEnableDegrade(retrofitInterface)) {
okHttpClientBuilder.addInterceptor(retrofitConfigBean.getRetrofitDegrade());
}
Expand All @@ -116,7 +120,8 @@ private OkHttpClient createOkHttpClient() throws IllegalAccessException, Invocat
}

private OkHttpClient.Builder createOkHttpClientBuilder() throws InvocationTargetException, IllegalAccessException {
RetrofitClient retrofitClient = retrofitInterface.getAnnotation(RetrofitClient.class);
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class);
Method method = findOkHttpClientBuilderMethod();
if (method != null) {
return (OkHttpClient.Builder)method.invoke(null);
Expand Down Expand Up @@ -158,11 +163,11 @@ private Method findOkHttpClientBuilderMethod() {

@SuppressWarnings("unchecked")
private List<Interceptor> findInterceptorByAnnotation() {
Annotation[] classAnnotations = retrofitInterface.getAnnotations();
Annotation[] classAnnotations = AnnotationUtils.getAnnotations(retrofitInterface);
List<Interceptor> interceptors = new ArrayList<>();
// 找出被@InterceptMark标记的注解。Find the annotation marked by @InterceptMark
List<Annotation> interceptAnnotations = new ArrayList<>();
for (Annotation classAnnotation : classAnnotations) {
for (Annotation classAnnotation : Objects.requireNonNull(classAnnotations)) {
Class<? extends Annotation> annotationType = classAnnotation.annotationType();
if (annotationType.isAnnotationPresent(InterceptMark.class)) {
interceptAnnotations.add(classAnnotation);
Expand Down Expand Up @@ -204,9 +209,9 @@ private List<Interceptor> findInterceptorByAnnotation() {
return interceptors;
}

private Retrofit createRetrofit()
throws InstantiationException, IllegalAccessException, InvocationTargetException {
RetrofitClient retrofitClient = retrofitInterface.getAnnotation(RetrofitClient.class);
private Retrofit createRetrofit() throws IllegalAccessException, InvocationTargetException {
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class);
String baseUrl = RetrofitUtils.convertBaseUrl(retrofitClient, retrofitClient.baseUrl(), environment);

OkHttpClient client = createOkHttpClient();
Expand Down
Expand Up @@ -2,6 +2,7 @@

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
Expand All @@ -15,6 +16,7 @@
@Target(ElementType.TYPE)
@Documented
@Import(RetrofitClientScannerRegistrar.class)
@Inherited
public @interface RetrofitScan {

/**
Expand Down
Expand Up @@ -6,6 +6,7 @@
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.context.EnvironmentAware;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.env.Environment;

import com.github.lianjiatech.retrofit.spring.boot.core.RetrofitClient;
Expand All @@ -29,7 +30,8 @@ public String parseResourceName(Method method) {
if (resourceName != null) {
return resourceName;
}
RetrofitClient retrofitClient = method.getDeclaringClass().getAnnotation(RetrofitClient.class);
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), RetrofitClient.class);
String baseUrl = RetrofitUtils.convertBaseUrl(retrofitClient, retrofitClient.baseUrl(), environment);
HttpMethodPath httpMethodPath = parseHttpMethodPath(method);
resourceName = formatResourceName(baseUrl, httpMethodPath);
Expand Down
Expand Up @@ -5,6 +5,7 @@
import java.lang.reflect.Proxy;

import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;

import com.github.lianjiatech.retrofit.spring.boot.core.RetrofitClient;

Expand All @@ -22,7 +23,8 @@ public class DegradeProxy implements InvocationHandler {

@SuppressWarnings("unchecked")
public static <T> T create(Object source, Class<T> retrofitInterface, ApplicationContext applicationContext) {
RetrofitClient retrofitClient = retrofitInterface.getAnnotation(RetrofitClient.class);
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(retrofitInterface, RetrofitClient.class);
Class<?> fallbackClass = retrofitClient.fallback();
Object fallback = null;
if (!void.class.isAssignableFrom(fallbackClass)) {
Expand Down
Expand Up @@ -30,38 +30,38 @@ public interface ResourceNameParser {
*/
default HttpMethodPath parseHttpMethodPath(Method method) {

if (method.isAnnotationPresent(HTTP.class)) {
HTTP http = method.getAnnotation(HTTP.class);
HTTP http = method.getAnnotation(HTTP.class);
if (http != null) {
return new HttpMethodPath(http.method(), http.path());
}

if (method.isAnnotationPresent(GET.class)) {
GET get = method.getAnnotation(GET.class);
GET get = method.getAnnotation(GET.class);
if (get != null) {
return new HttpMethodPath("GET", get.value());
}

if (method.isAnnotationPresent(POST.class)) {
POST post = method.getAnnotation(POST.class);
POST post = method.getAnnotation(POST.class);
if (post != null) {
return new HttpMethodPath("POST", post.value());
}

if (method.isAnnotationPresent(PUT.class)) {
PUT put = method.getAnnotation(PUT.class);
PUT put = method.getAnnotation(PUT.class);
if (put != null) {
return new HttpMethodPath("PUT", put.value());
}

if (method.isAnnotationPresent(DELETE.class)) {
DELETE delete = method.getAnnotation(DELETE.class);
DELETE delete = method.getAnnotation(DELETE.class);
if (delete != null) {
return new HttpMethodPath("DELETE", delete.value());
}

if (method.isAnnotationPresent(HEAD.class)) {
HEAD head = method.getAnnotation(HEAD.class);
HEAD head = method.getAnnotation(HEAD.class);
if (head != null) {
return new HttpMethodPath("HEAD", head.value());
}

if (method.isAnnotationPresent(PATCH.class)) {
PATCH patch = method.getAnnotation(PATCH.class);
PATCH patch = method.getAnnotation(PATCH.class);
if (patch != null) {
return new HttpMethodPath("PATCH", patch.value());
}
throw new UnsupportedOperationException("unsupported method!" + method);
Expand Down
Expand Up @@ -43,7 +43,8 @@ public void loadDegradeRules(Class<?> retrofitInterface) {
continue;
}
Resilience4jDegrade resilience4jDegrade =
AnnotationExtendUtils.findAnnotationIncludeClass(method, Resilience4jDegrade.class);
AnnotationExtendUtils.findMergedAnnotation(method, method.getDeclaringClass(),
Resilience4jDegrade.class);
if (resilience4jDegrade == null) {
continue;
}
Expand Down
Expand Up @@ -42,7 +42,8 @@ public void loadDegradeRules(Class<?> retrofitInterface) {
}
// 获取熔断配置
SentinelDegrade sentinelDegrade =
AnnotationExtendUtils.findAnnotationIncludeClass(method, SentinelDegrade.class);
AnnotationExtendUtils.findMergedAnnotation(method, method.getDeclaringClass(),
SentinelDegrade.class);
if (sentinelDegrade == null) {
continue;
}
Expand All @@ -61,7 +62,8 @@ public void loadDegradeRules(Class<?> retrofitInterface) {
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Method method = Objects.requireNonNull(request.tag(Invocation.class)).method();
if (AnnotationExtendUtils.findAnnotationIncludeClass(method, SentinelDegrade.class) == null) {
if (AnnotationExtendUtils.findMergedAnnotation(method, method.getDeclaringClass(),
SentinelDegrade.class) == null) {
return chain.proceed(request);
}
String resourceName = parseResourceName(method);
Expand Down
Expand Up @@ -7,6 +7,7 @@
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotatedElementUtils;

import com.github.lianjiatech.retrofit.spring.boot.core.ErrorDecoder;
import com.github.lianjiatech.retrofit.spring.boot.core.RetrofitClient;
Expand All @@ -30,7 +31,8 @@ public class ErrorDecoderInterceptor implements Interceptor, ApplicationContextA
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Method method = Objects.requireNonNull(request.tag(Invocation.class)).method();
RetrofitClient retrofitClient = method.getDeclaringClass().getAnnotation(RetrofitClient.class);
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), RetrofitClient.class);
ErrorDecoder errorDecoder =
AppContextUtils.getBeanOrNew(applicationContext, retrofitClient.errorDecoder());
boolean decoded = false;
Expand Down
Expand Up @@ -5,6 +5,7 @@
import java.net.URI;
import java.util.Objects;

import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.StringUtils;

import com.github.lianjiatech.retrofit.spring.boot.core.RetrofitClient;
Expand Down Expand Up @@ -32,7 +33,8 @@ public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Method method = Objects.requireNonNull(request.tag(Invocation.class)).method();
Class<?> declaringClass = method.getDeclaringClass();
RetrofitClient retrofitClient = declaringClass.getAnnotation(RetrofitClient.class);
RetrofitClient retrofitClient =
AnnotatedElementUtils.findMergedAnnotation(declaringClass, RetrofitClient.class);
String baseUrl = retrofitClient.baseUrl();
if (StringUtils.hasText(baseUrl)) {
return chain.proceed(request);
Expand Down
Expand Up @@ -4,6 +4,8 @@
import java.lang.reflect.Method;
import java.util.Objects;

import org.springframework.core.annotation.AnnotatedElementUtils;

import com.github.lianjiatech.retrofit.spring.boot.config.LogProperty;

import lombok.extern.slf4j.Slf4j;
Expand All @@ -30,8 +32,7 @@ public LoggingInterceptor(LogProperty logProperty) {
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Method method = Objects.requireNonNull(request.tag(Invocation.class)).method();
// 获取重试配置
Logging logging = method.getDeclaringClass().getAnnotation(Logging.class);
Logging logging = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Logging.class);
if (!needLog(logging)) {
return chain.proceed(request);
}
Expand Down
Expand Up @@ -33,7 +33,7 @@ public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Method method = Objects.requireNonNull(request.tag(Invocation.class)).method();
// 获取重试配置
Retry retry = AnnotationExtendUtils.findAnnotationIncludeClass(method, Retry.class);
Retry retry = AnnotationExtendUtils.findMergedAnnotation(method, method.getDeclaringClass(), Retry.class);
if (!needRetry(retry)) {
return chain.proceed(request);
}
Expand Down
Expand Up @@ -3,6 +3,8 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.springframework.core.annotation.AnnotatedElementUtils;

import lombok.experimental.UtilityClass;

/**
Expand All @@ -16,15 +18,17 @@ public class AnnotationExtendUtils {
* 查找方法及其类上的指定注解,优先返回方法上的。
* @param <A> 注解泛型参数
* @param method 方法
* @param clazz 类型
* @param annotationType 注解类型
* @return 方法及其类上的指定注解。
*/
public static <A extends Annotation> A findAnnotationIncludeClass(Method method, Class<A> annotationType) {
A annotation = method.getAnnotation(annotationType);
public static <A extends Annotation> A findMergedAnnotation(Method method, Class<?> clazz,
Class<A> annotationType) {
A annotation = AnnotatedElementUtils.findMergedAnnotation(method, annotationType);
if (annotation != null) {
return annotation;
}
return method.getDeclaringClass().getAnnotation(annotationType);
return AnnotatedElementUtils.findMergedAnnotation(clazz, annotationType);
}

/**
Expand All @@ -36,11 +40,11 @@ public static <A extends Annotation> A findAnnotationIncludeClass(Method method,
*/
public static <A extends Annotation> boolean isAnnotationPresentIncludeMethod(Class<?> clazz,
Class<A> annotationType) {
if (clazz.isAnnotationPresent(annotationType)) {
if (AnnotatedElementUtils.findMergedAnnotation(clazz, annotationType) != null) {
return true;
}
for (Method method : clazz.getMethods()) {
if (method.isAnnotationPresent(annotationType)) {
if (AnnotatedElementUtils.findMergedAnnotation(method, annotationType) != null) {
return true;
}
}
Expand Down

0 comments on commit c1f88b8

Please sign in to comment.