服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Feign如何自定义注解翻译器

Feign如何自定义注解翻译器

2022-09-28 15:13chengqiuming Java教程

这篇文章主要介绍了Feign如何自定义注解翻译器,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Feign自定义注解翻译器

新建自定义注解MyUrl

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package org.crazyit.cloud.contract; 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
//这个注解只能定义方法
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyUrl {
    //为注解配置两个属性
    String url();
    String method();
}

新建接口,使用MyUrl注解

?
1
2
3
4
5
package org.crazyit.cloud.contract; 
public interface ContractClient { 
    @MyUrl(url = "/hello", method = "GET")
    public String hello();
}

定义注解翻译器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package org.crazyit.cloud.contract; 
import java.lang.annotation.Annotation;
import java.lang.reflect.Method; 
import feign.Contract.BaseContract;
import feign.MethodMetadata; 
public class MyContract extends BaseContract {
 
    @Override
    protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
        // 处理类级别注解
    }
 
    @Override
    protected void processAnnotationOnMethod(MethodMetadata data,
            Annotation annotation, Method method) {
        // 注解是MyUrl类型的,才处理
        if(MyUrl.class.isInstance(annotation)) {
            MyUrl myUrl = method.getAnnotation(MyUrl.class);
            String url = myUrl.url();
            String httpMethod = myUrl.method();
            data.template().method(httpMethod);
            data.template().append(url);
        }
    }
 
    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata data,
            Annotation[] annotations, int paramIndex) {
        // 处理参数级别注解
        return false;
   
}

测试类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.crazyit.cloud.contract; 
import org.crazyit.cloud.jaxrs.RsClient; 
import feign.Feign;
import feign.jaxrs.JAXRSContract;
 
public class ContractMain { 
    public static void main(String[] args) {
        ContractClient client = Feign.builder()
                .contract(new MyContract())
                .target(ContractClient.class,
                "http://localhost:8080");
        String result = client.hello();
        System.out.println(result);
    }
 
}

启动服务类

测试

Hello World

Feign注解说明

Feign是常用的微服务rpc调用框架,下面对一些注解说明

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface FeignClient {
    /**
     * value和name的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。
     *
     */
    @AliasFor("name")
    String value() default "";
    /**
     * serviceId已经废弃了,直接使用name即可。
     */
    /** @deprecated */
    @Deprecated
    String serviceId() default "";
    /**
     *某个服务提供的接口不止定义在一个类中,这样启动时会报Bean的名称冲突。
     * 解决方法:
     * 1:参数配置添加
     *  spring.main.allow-bean-definition-overriding=true
     *
     * 2:给每个client指定contextid
     *
     */
    String contextId() default "";
    /**
     *
     *  在注册Feign Client Configuration的时候需要一个名称,名称是通过getClientName方法获取的.
     *  查看源码可知,如果配置了contextId就会用contextId,
     *  如果没有配置就会去value,然后是name,最后是serviceId。
     *  默认都没有配置,当出现一个服务有多个Feign Client的时候就会报错了。
     *
     *  其次的作用是在注册FeignClient中,contextId会作为Client 别名的一部分,如果配置了qualifier优先用qualifier作为别名。
     *
     */
    /**
     *见 value
     *
     */
    @AliasFor("value")
    String name() default "";
    /**
     *
     * 在注册FeignClient中,指定client别名
     *
     */
    String qualifier() default "";
    /**
     *
     * url用于配置指定服务的地址,相当于直接请求这个服务,不经过Ribbon的服务选择。像调试等场景可以使用。
     *
     */
    String url() default "";
    /**
     *
     * 当调用请求发生404错误时,decode404的值为true,那么会执行decoder解码,否则抛出异常。
     *
     */
    boolean decode404() default false;
    /**
     *
     * configuration是配置Feign配置类,在配置类中可以自定义Feign的Encoder、Decoder、LogLevel、Contract等。
     * 具体查看FeignConfiguration类
     *
     */
    Class<?>[] configuration() default {};
    /**
     *
     * 定义容错的处理类,也就是回退逻辑,fallback的类必须实现Feign Client的接口,无法知道熔断的异常信息。
     *
     *
     *
     *
     * 举例:
     * //实现调用接口方法
     * @Component
     * public class UserRemoteClientFallback implements UserRemoteClient {
     *      @Override
     *      public User getUser(int id) {
     *          return new User(0, "默认fallback");
     *      }
     * }
     *
     * //user服务
     * @FeignClient(value = "user", fallback = UserRemoteClientFallback.class)
     * public interface UserRemoteClient {
     *      @GetMapping("/user/get")
     *      public User getUser(@RequestParam("id")int id);
     * }
     *
     *
     */
    Class<?> fallback() default void.class;
    /**
     *
     * 也是容错的处理,可以知道熔断的异常信息。熔断的另一种处理方法。
     *
     * //服务类作为参数传入FallbackFactory模板参数
     * @Component
     * public class UserRemoteClientFallbackFactory implements FallbackFactory<UserRemoteClient> {
     *  private Logger logger = LoggerFactory.getLogger(UserRemoteClientFallbackFactory.class);
     *
     *  @Override
     *  public UserRemoteClient create(Throwable cause) {
     *      return new UserRemoteClient() {
     *          @Override
     *          public User getUser(int id) {
     *              logger.error("UserRemoteClient.getUser异常", cause);
     *              return new User(0, "默认");
     *          }
     *      };
     *  }
     * }
     *
     */
    Class<?> fallbackFactory() default void.class;
    /**
     *
     * path定义当前FeignClient访问接口时的统一前缀
     * 比如接口地址是/user/get, 如果你定义了前缀是user, 那么具体方法上的路径就只需要写/get 即可。
     *
     * @FeignClient(name = "user", path="user")
     * public interface UserRemoteClient {
     *      @GetMapping("/get")
     *      public User getUser(@RequestParam("id") int id);
     * }
     *
     */
    String path() default "";
    /**
     *  primary对应的是@Primary注解,默认为true.
     *  官方这样设置也是有原因的。当我们的Feign实现了fallback后,也就意味着Feign Client有多个相同的Bean在Spring容器中,
     *  当我们在使用@Autowired(建议使用@Resource注入对象)进行注入的时候,不知道注入哪个,所以我们需要设置一个优先级高的,@Primary注解就是干这件事情的。
     *
     *
     */
    boolean primary() default true;
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/chengqiuming/article/details/81140916

延伸 · 阅读

精彩推荐