Spring Cloud_13_Feign第三方註解與請求攔截器

Feign第三方註解與請求攔截器

1、使用第三方直接

1.1、引入依賴

  • 如果想使用JAXRS規範來註解,可以使用Feign的“feign-jaxrs”模塊
<!-- Feign 對 JAXRS 的支持 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-jaxrs</artifactId>
    <version>9.5.0</version>
</dependency>
<!-- JAXRS -->
<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>jsr311-api</artifactId>
    <version>1.1.1</version>
</dependency>

1.2、修改客戶端接口

package com.atm.cloud;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

import feign.RequestLine;

public interface HelloClient {

    /*@RequestLine("GET /hello")
    public String sayHello();*/

    @GET
    @Path("/hello")
    public String sayHello();
}

1.3、請求測試

package com.atm.cloud;

import feign.Feign;
import feign.gson.GsonEncoder;
import feign.jaxrs.JAXRSContract;

public class HelloClient {

    public static void main(String[] args) {

        //設置了 JAXRSContract 類,Feign 就知道如何處理 JAXRS 的相關注解
        HelloClient helloClient = Feign.builder().contract(new JAXRSContract())
                .target(HelloClient.class, "http://localhost:8080/");

        String result = helloClient.sayHello();

        System.out.println("接口響應內容:" + result);
    }
}
  • 請求結果與之前一樣

2、Feign解析第三方註解原理

  • 設置了 JAXRSContract 類,Feign 就知道如何處理 JAXRS 的相關注解
  • JAXRSContract繼承了BaseContract類,BaseContract類實現了Contract接口
  • 簡單來說,一個Contract就相當於一個翻譯器
  • Feign本身並不知道第三方註解的含義,而是通過實現一個翻譯器(Contract)來告訴Feign
  • 下面,我們首先將自定義註解告訴Feign,然後Feign通過翻譯器解析我們自定義的註解

2.1、自定義註解

package com.atm.cloud;

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 MyAnnott {

    // 定義url和method屬性
    String url();

    String method();

}

2.2、修改客戶端接口

package com.atm.cloud;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

import feign.RequestLine;

public interface HelloClient {

    /*@RequestLine("GET /hello")
    public String sayHello();*/

    /*@GET
    @Path("/hello")
    public String sayHello();*/

    @MyAnnott(method="GET",url="/hello")
    public String sayHello();
}

2.3、自定義翻譯器

package com.atm.cloud;

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 metadata,
            Class<?> arg1) {

    }

    @Override
    protected void processAnnotationOnMethod(MethodMetadata metadata,
            Annotation annotation, Method method) {

        //註解是MyAnnott類型,才解析
        if(MyAnnott.class.isInstance(annotation)){
            // 獲取註解的實例
            MyAnnott myAnnott = method.getAnnotation(MyAnnott.class);
            // 獲取服務的 url
            String url = myAnnott.url();
            // 獲取配置的 HTTP 方法
            String httpMethod = myAnnott.method();
            // 將值設置到模板中
            metadata.template().method(httpMethod);
            metadata.template().append(url);
        }
    }

    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata metadata,
            Annotation[] annotations, int i) {
        return false;
    }

}
  • 在 MyContract 類中,需要實現三個方法,分別是處理類註解、處理方法註解、處理參數註解的方法
  • 我們只定了一個方法註解@MyRul,因此實現processAnnotationOnMethod 即可
  • 通過 Method 的 getAnnotation 獲取 MyUrl的實例,將 MyUrl 的 url、method 屬性分別設置到 Feign 的模板中

2.4、請求測試

package com.atm.cloud;

import feign.Feign;
import feign.gson.GsonEncoder;
import feign.jaxrs.JAXRSContract;

public class HelloMain {

    public static void main(String[] args) {

        // 獲取服務接口
        HelloClient helloClient = Feign.builder().contract(new MyContract())
                .target(HelloClient.class, "http://localhost:8080/");
        // 請求 Hello World 接口
        String result = helloClient.sayHello();
        System.out.println(" 接口響應內容:" + result);
    }
}
  • Contract 實際上承擔的是一個翻譯的作用,將第三方(或者自定義)註解的作用告訴 Feign

3、請求攔截器

  • 在發送請求的時候需要設置公共信息(權限、請求類型等)

3.1、編寫請求攔截器

package com.atm.cloud.interceptor;

import feign.RequestInterceptor;
import feign.RequestTemplate;

public class MyInterceptor implements RequestInterceptor {

    public void apply(RequestTemplate template) {
        //設置請求頭信息(這樣就可以不需要在每一個方法中都設置了)
        //template.header("Content-Type", "application/json");
        System.out.println("   --->>> 這是自定義攔截器   <<<---  ");
    }

}

3.2、運行測試

package com.atm.cloud.interceptor;

import com.atm.cloud.HelloClient;

import feign.Feign;

public class InterceptorMain {

    public static void main(String[] args) {
        HelloClient helloClient = Feign.builder()
                .requestInterceptor(new MyInterceptor())
                .target(HelloClient.class, "http://localhost:8080/");

        String result=helloClient.sayHello();

        System.out.println(result);
    }
}

4、接口日誌

  • 默認情況下,接口不會記錄接口日誌
  • 如果想要了解接口的調用情況,可以配置接口日誌

4.1、運行測試

package com.atm.cloud.log;

import com.atm.cloud.HelloClient;

import feign.Feign;
import feign.Logger;

public class LogMain {

    public static void main(String[] args) {
        /**
         * NONE:    默認值,不記錄日誌
         * BASIC:   記錄請求方法、URL、響應狀態代碼和執行時間
         * HEADERS: 除BASIC記錄日誌外,還會記錄請求頭和響應頭的信息
         * FULL:    在HEADERS的基礎上,請求和響應的元數據,都會保存
         */
        HelloClient helloClient = Feign.builder().logLevel(Logger.Level.FULL)
                .logger(new Logger.JavaLogger().appendToFile("logs/main.log"))
                .target(HelloClient.class, "http://localhost:8080/");

        String result = helloClient.sayHello();

        System.out.println(result);
    }
}
  • 需要創建日誌文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章