OpenFeign-远程调用((Feign的使用方法))

最佳实践(Feign的使用方法)

最佳实践, 其实也就是经过历史的迭代, 在项⽬中的实践过程中, 总结出来的最好的使⽤⽅式.

通过观察, 我们也能看出来, Feign的客⼾端与服务提供者的controller代码⾮常相似.

Feign 客⼾端:

@FeignClient(value = "product-service", path = "/product")
public interface ProductApi {
 @RequestMapping("/{productId}")
 ProductInfo getProductById(@PathVariable("productId") Integer productId);
}

服务提供⽅Controller

@RequestMapping("/product")
@RestController
public class ProductController {
 @RequestMapping("/{productId}")
 public ProductInfo getProductById(@PathVariable("productId") Integer 
productId){
 //...
 }
}

有没有⼀种⽅法可以简化这种写法呢?

方案一:Feign 继承⽅式

官⽅推荐Feign的使⽤⽅式为继承的⽅式, 但是企业开发中, 更多是把Feign接⼝抽取为⼀个独⽴的模块

(做法和继承相似, 但理念不同).

操作⽅法:

将Feign的Client抽取为⼀个独⽴的模块, 并把涉及到的实体类等都放在这个模块中, 打成⼀个Jar. 服务

消费⽅只需要依赖该Jar包即可. 这种⽅式在企业中⽐较常⻅, Jar包通常由服务提供⽅来实现.

1.创建⼀个module:

2.引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

3.编写接⼝

public interface ProductInterface {

    @RequestMapping("/{productId}")
    ProductInfo getProductInfo(@PathVariable("productId") Integer productId);

    @RequestMapping("/p1")
    String p1(@RequestParam("id") Integer id);

    @RequestMapping("/p2")
    String p2(@RequestParam("id") Integer id,@RequestParam("name") String name);

    @RequestMapping("/p3")
    String p3(@SpringQueryMap ProductInfo productInfo);

    @RequestMapping("/p4")
    String p4(@RequestBody ProductInfo productInfo);
}

相当于把ProductApi 和 ProductInfo 搬到 product-api 这个model里

4.打jar包

通过Maven打包

install:把当前工程打成 jar 包,放在maven本地仓库(不是远程仓库)

下面这个样子就代表打包成功,

我们在复制包的路径看是否存在

5.修改服务提供⽅代码

服务提供⽅实现接⼝ ProductInterface

@RestController
@RequestMapping("/product")
public class ProductController implements ProductInterface {

    @Autowired
    private ProductService productService;

    @RequestMapping("/{productId}")
    public ProductInfo getProductById(@PathVariable("productId") Integer productId){
        return productService.selectProductById(productId);
    }

    @RequestMapping("/p1")
    public String p1(Integer id){
        return "product-service 接收到的参数,id=" + id;
    }

    @RequestMapping("/p2")
    public String p2(Integer id,String name){
        return "product-service 接收到的参数,id=" + id + "name = " + name;
    }

    @RequestMapping("/p3")
    public String p3(ProductInfo productInfo){
        return "product-service 接收到的参数 productInfo =  " + productInfo.toString();
    }

    @RequestMapping("/p4")
    public String p4(@RequestBody ProductInfo productInfo){
        return  "product-service 接收到的参数 productInfo =  " + productInfo.toString();
    }

}

由于我们要是用ProductInterface这个接口,刚才已经把product-api这个model已经达成jar包了,我们就可以把jar包引入,从而就可以实现ProductInterface接口了。

ProductInfo这个实体类也是,product-api里已经存在这个实体类了,那么product-service里的就可以删除了。

使用快捷键,按住 alt + 回车(enter),可以快速引入我们需要的jar包。

成功引入我们刚才创建好的jar包。

6.修改服务消费⽅

服务消费⽅继承ProductInterface

@FeignClient(value = "product-service" , path = "/product")
public interface ProductApi extends ProductInterface {

}

7.测试

远程调⽤:127.0.0.1:8080/order/1

方案二:Feign 抽取⽅式(抽取的模块,通常是由服务的提供方来写)

官⽅推荐Feign的使⽤⽅式为继承的⽅式, 但是企业开发中, 更多是把Feign接⼝抽取为⼀个独⽴的模块

(做法和继承相似, 但理念不同).

继承:在使用的时候仍需要再声明一个 Feign 的接口(ProductApi)

操作⽅法:

将Feign的Client抽取为⼀个独⽴的模块, 并把涉及到的实体类等都放在这个模块中, 打成⼀个Jar. 服务

消费⽅只需要依赖该Jar包即可. 这种⽅式在企业中⽐较常⻅, Jar包通常由服务提供⽅来实现.

1.创建一个model

2.引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

3.完成抽取

把order-service模块里的 ProductApi 和 ProductInfo 抽取到 product-api。

4.打包 install

通过Maven打包

install:把当前工程打成 jar 包,放在maven本地仓库(不是远程仓库)

下面这个样子就代表打包成功,

我们在复制包的路径看是否存在

5.服务调用方,引入抽取出来的模块(order-service)

  1. 删除 ProductApi, ProductInfo
  2. 引⼊依赖
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>product-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

修改项⽬中ProductApi, ProductInfo的路径为product-api中的路径

  1. 指定扫描类: ProductApi(最重要,必不可少)

由于我们进行了抽取,ProductApi就属于第三方的了,我们又需要依赖注入@Autowired ,而我们的扫描路径只能扫描启动类的同一级文件及子文件,所以为了能够成功注入ProductApi我们需要 在启动类添加扫描路径

@EnableFeignClients(basePackages = {"com.bite.api"})

完整代码

@EnableFeignClients(basePackages = {"com.bite.api"})
@SpringBootApplication
public class OrderServiceApplication {
	 public static void main(String[] args) {
		 SpringApplication.run(OrderServiceApplication.class, args);
	 }
}

或者也可以指定需要加载的Feign客⼾端(通过@EnableFeignClients(clients = {ProductApi.class}))


@EnableFeignClients(clients = {ProductApi.class})
@SpringBootApplication
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class,args);
    }
}

6.测试

远程调⽤:127.0.0.1:8080/order/1

### OpenFeign动态远程调用实现方式 OpenFeign 是一种声明式的 HTTP 客户端工具,它允许开发者像调用本地方法一样调用远程服务[^1]。然而,默认情况下,OpenFeign 的接口定义是静态的,在开发阶段就已经固定下来。如果需要支持 **动态远程调用**,可以通过一些扩展机制来实现。 以下是通过 OpenFeign 实现动态远程调用的一种常见方案: #### 1. 使用 Feign.Builder 手动构建 Feign 客户端 `Feign.Builder` 提供了一种灵活的方式来创建动态的 Feign 客户端实例。这种方式不需要提前定义固定的接口,而是可以在运行时指定目标 URL 和请求参数。 ```java import feign.Feign; import feign.RequestLine; public class DynamicFeignExample { public static void main(String[] args) { String targetUrl = "http://example.com/api"; // 动态设置的目标URL MyDynamicInterface dynamicClient = Feign.builder() .target(MyDynamicInterface.class, targetUrl); // 调用远程方法 String response = dynamicClient.getSomeData(); System.out.println(response); } interface MyDynamicInterface { @RequestLine("GET /data") String getSomeData(); // 动态调用方法 } } ``` 上述代码展示了如何使用 `Feign.Builder` 创建一个动态的 Feign 客户端,并将其指向不同的目标地址[^4]。 --- #### 2. 结合 Spring Cloud 自定义配置 Spring Cloud 中集成了 OpenFeign 支持,因此也可以利用其灵活性来自定义动态调用逻辑。具体来说,可以基于以下步骤完成: ##### (1) 配置动态目标地址 在实际应用中,可能需要根据业务需求动态调整目标服务地址。这可以通过自定义 Bean 来实现。 ```java import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient(name = "dynamic-client", url = "${dynamic.url}") // 动态url可以从配置文件或者环境变量读取 public interface DynamicFeignClient { @GetMapping("/api/data") String getData(); } ``` 在此示例中,`${dynamic.url}` 可以从配置文件或程序启动时传入的参数中获取,从而实现动态切换目标地址的功能[^5]。 --- ##### (2) 运行时修改目标地址 除了通过配置文件设定外,还可以在运行期间动态更改目标地址。例如,借助于 `Targeter` 或者手动替换 `LoadBalancerClient` 的行为。 ```java import org.springframework.beans.factory.ObjectFactory; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.context.ApplicationContext; import feign.Contract; import feign.Feign; import feign.codec.Decoder; import feign.codec.Encoder; public class CustomFeignBuilder { public Object createDynamicClient(Class<?> type, String url) { Encoder encoder = new SpringEncoder(new HttpMessageConverters()); Decoder decoder = new ResponseEntityDecoder(new SpringDecoder((ObjectFactory<HttpMessageConverters>) () -> null)); return Feign.builder() .encoder(encoder) .decoder(decoder) .contract(new Contract.Default()) .target(type, url); // 动态传递目标URL } } ``` 此代码片段展示了一个通用的工厂类,用于按需生成针对不同 URL 的 Feign 客户端实例[^3]。 --- #### 3. 利用反射技术增强动态能力 对于更加复杂的场景,比如完全未知的服务名和方法签名,可以考虑结合 Java 反射以及动态代理技术。不过需要注意的是,这种方法会增加一定的复杂度并可能导致性能下降。 --- ### 总结 以上介绍了几种常见的 OpenFeign 动态远程调用实现方式,包括但不限于使用 `Feign.Builder` 构建动态客户端、结合 Spring Cloud 自定义配置以及引入反射技术等手段[^2]。每种方法都有各自的适用范围和优缺点,应根据具体的业务需求选择合适的解决方案。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值