1. 程式人生 > >Fegin根據配置項請求不同的地址實現方法

Fegin根據配置項請求不同的地址實現方法

在專案過程中,可能會遇到比較奇葩的需求,比如:使用@FeginClient註解的介面只能配置一個url,但我又想根據不同的配置項決定我使用哪個url,當然,前提是這兩個url屬於同一個專案的不同的部署環境。

眾所周知,feign只是個宣告式呼叫,沒有決策機制,所以想通過feign自己來實現是不可能了。

我的實現方式:

1.這兩個FeignClient繼承同一個介面,因為所有的方法都相同,把方法都寫到這個父類介面中,兩個子類介面body體為空即可。

2.配置檔案中增加一個配置項,如果這個配置項等於某個值,就呼叫一個FeignClient,否則,呼叫另一個。

下面上程式碼:

公共介面(不需要加@Service和@FeginClient註解):


public interface AssetService {
   
    @PostMapping(value = "/v2/model/nodes/{namespace}/access")
    public Response getNodeById( @PathVariable("namespace") String namespace,
            @RequestBody AccessNodeParam accessNodeParam);

    @PostMapping("/opcua/getNodesByBrowsePath")
    public @ResponseBody
    Response getNodesByBrowsePath(@RequestBody List<OPCUABrowsePath> opcuaBrowsePaths);
}

兩個子類介面(需要加@FeginClient和@Service註解):

介面1:

@Service
@FeignClient(name = "MS-ASSET", url="${assetSrv.url1}")
public interface AssetQueryServiceOfDevice extends AssetService{}

介面2:

@Service
@FeignClient(name = "MS-ASSET", url="${assetSrv.url2}")
public interface AssetQueryServiceOfProject extends AssetService{}

使用這兩個FeginClient:

在Controller中使用這兩個FeginClient的方法:

(1)給Controller的增加構造方法

(2)在Controller的構造方法中將@Value獲取的變數和這兩個FeginClient注入進去,這裡要注意:不能直接使用@Value獲取配置檔案中的配置項,然後直接在AggQueryController 的構造方法中使用,因為:構造器的執行要早於@Value和@Autowired,構造方法執行時所有的@Value或@Autowired註解的物件此時都還為空,導致他們一直為空!

所以要把@Value獲取的配置項通過一個配置類獲取,然後將這個配置類通過構造方法注入到AggQueryController !

@RequestMapping("/query")
@RequestController
public class AggQueryController {
    private static final Logger logger = LoggerFactory.getLogger(AggQueryController.class);

    private String assetRequestFlag;

    private AssetService assetService;

    /**
     * 將配置資訊通過一個配置類獲取,然後在構造器中注入;
否則,因為構造器的執行要早於@Value和@Autowired,會導致所有的物件都為空
     * @param config
     */
    public AggQueryController(AggQueryConfig config){
        this.assetRequestFlag= config.getAssetRequest();
        
        assetService = config.getAssetService();
    }
}

(3)配置類(用@Configuration註解的好處是能保證例項化優先順序比較高):

@Configuration
public class AggQueryConfig {
    @Value("${assetSrv.requestFlag}")
    private String assetRequest;

    @Autowired
    private AssetQueryService assetQueryService;

    @Autowired
    private AssetQueryServiceOfProject assetQueryServiceOfProject;

    @Autowired
    private TimeSeriesService timeSeriesService;

    public AssetService getAssetService(){
        if(StringUtils.equalsIgnoreCase("device", assetRequest)){
            return assetQueryService;
        }
        return assetQueryServiceOfProject;
    }
}

這樣,在AggQueryController中的其他方法中就可以使用assetService了。