首頁 > 軟體

Feign如何自定義註解翻譯器

2022-03-16 19:00:34

Feign自定義註解翻譯器

新建自定義註解MyUrl

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註解

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

定義註解翻譯器

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;
    } 
}

測試類

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呼叫框架,下面對一些註解說明

@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;
}

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com