feign 同一个服务编写多个远程调用实例 解决办法

问题

在微服务架构中,当我们需要进行服务间调用时可以选择feign组件,现在遇到的问题是:
	当同一个服务,声明多个feign实例时,启动时直接报错

错误信息

Cannot define alias 'basic-dataFeignClient' for name 'com.csbr.pharmacy.chain.cloud.service.operation.OperationFeignClient': It is already registered for name 'com.csbr.pharmacy.chain.cloud.service.BasicDataCommonFeignClient'.

猜测是因为@FeignClient注解的处理类在生成代理类,把代理类放入spring工厂中时,指定的名字规则就是 服务名+FeignClient,所以当有多个实例时,直接实例化失败

解决办法

通过 Feign.builder() 手动生成代理类

配置类

package com.csbr.pharmacy.chain.cloud.configurations;

import com.csbr.pharmacy.chain.cloud.service.operation.OperationFeignClient;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import feign.Contract;
import feign.Feign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author kangxuan
 * @date 2019/1/16 0016 11:13.
 * @Description: 自定义 feign实例 配置
 */
@Configuration
public class FeignClientConfig {
	/**
	* FeignClientFactoryBean 该工厂类中 设置builder属性时就是通过该对象,源码中可看到
	*/
    @Autowired
    private FeignContext feignContext;

	/**
	* 通过注入Eureka实例对象,就不用手动指定url,只需要指定服务名即可
	*/
    @Autowired
    private EurekaClient eurekaClient;


    private <T> T create(Class<T> clazz,String serverId){
        InstanceInfo nextServerFromEureka = eurekaClient.getNextServerFromEureka(serverId,false);
        return Feign.builder()
                .encoder(feignContext.getInstance(serverId,feign.codec.Encoder.class))
                .decoder(feignContext.getInstance(serverId,feign.codec.Decoder.class))
                .contract(feignContext.getInstance(serverId, Contract.class))
                .target(clazz, nextServerFromEureka.getHomePageUrl());

    }

	  @Bean
	   public OperationFeignClient getOperationFeignClient(){
	       return create(OperationFeignClient.class,"basic-data");
	   }
}

OperationFeignClient 类

package com.csbr.pharmacy.chain.cloud.service.operation;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * @author kangxuan
 * @date 2018/12/28 0028 10:15.
 * @Description: 运营端专用 feign组件
 */
public interface OperationFeignClient {

    /**
     * 添加数据
     * @param tableName 表名
     * @param data 添加的实体类
     * @return
     */
    @RequestMapping(value = "/data/{tableName}/add",method = RequestMethod.POST)
    String  create(
            @PathVariable("tableName") String tableName,
            @RequestBody Object data);

}

@FeignClient注解类

package com.csbr.pharmacy.chain.cloud.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * @author kangxuan
 * @date 2018/12/28 0028 10:15.
 * @Description: 基础数据服 调用 公共组件
 */
@FeignClient(serviceId = "basic-data",name = "base")
public interface  BasicDataCommonFeignClient  {

    /**
     * 添加数据
     * @param tableName 表名
     * @param data 添加的实体类
     * @return
     */
    @RequestMapping(value = "/data/{tableName}/add",method = RequestMethod.POST)
    String  create(
            @PathVariable("tableName") String tableName,
            @RequestBody Object data);

    /**
     * 根据id查询数据
     * @param tableName 表名
     * @param guid guid
     * @return
     */
    @RequestMapping(value = "/data/{tableName}/{guid}",method = RequestMethod.GET)
    String selectByGuid(
            @PathVariable("tableName") String tableName,
            @PathVariable("guid") String guid);

    /**
     * 根据条件查询
     * @param tableName
     * @param data
     * @return
     */
    @RequestMapping(value = "/data/{tableName}/search",method = RequestMethod.POST)
    String selectByConditions(
            @PathVariable("tableName") String tableName,
            Object data);


    /**
     * 更新数据
     * @param tableName 表名
     * @param guid guid
     * @return
     */
    @RequestMapping(value = "/data/{tableName}/{guid}",method = RequestMethod.PUT)
    String update(
            @PathVariable("tableName") String tableName,
            @PathVariable("guid") String guid,
            @RequestBody Object data);
}

这样两个 feign 接口都能进行使用了

Feign 是 Netflix 开源的一款声明式 HTTP 客户端库,用于简化远程调用和 REST API 的使用。静态方法调用 Feign 可以通过直接使用预定义的接口(如 `Ribbon` 或 `Hystrix` 等)创建客户端实例,并发起请求。 ### 静态方法调用 Feign 的步骤: 1. **导入依赖**:首先,在项目中添加 Feign 相关的 Maven 或 Gradle 依赖。例如,在 Maven 中可以添加以下依赖: ```xml <dependency> <groupId>com.github(feign)</groupId> <artifactId>feign</artifactId> <version>(最新版本)</version> </dependency> ``` 2. **创建配置文件**:通常会有默认的配置类用于全局设置,如 `Feign.Builder`。但你也可以自定义配置类来自定义特定的行为。 3. **定义接口**:编写一个接口并注解 `@FeignClient` 来指定这个服务的具体信息,如服务名称、URL 和超时时间等。 ```java @FeignClient(name = "my-service", url = "${my-service.url}", configuration = YourConfiguration.class) public interface MyServiceClient { @GetMapping("/health") HealthCheckResponse health(); } ``` 4. **注入接口**:在需要调用该服务的类中,通过构造函数或依赖注入的方式注入上述接口,然后就可以像调用本地方法一样使用了。 5. **发起请求**:调用接口中的方法即可发起远程调用。 ### 示例代码: 假设我们需要调用名为 `MyService` 的远程服务,其提供的接口包含了一个 `/health` 路径的方法返回健康检查结果。 ```java @Service public class ServiceClass { private final MyServiceClient myServiceClient; @Autowired public ServiceClass(MyServiceClient myServiceClient) { this.myServiceClient = myServiceClient; } public void checkHealth() { try { HealthCheckResponse response = myServiceClient.health(); System.out.println("Health status: " + response.getStatus()); } catch (Exception e) { e.printStackTrace(); } } } ``` ### 注意事项: - **容错处理**:Feign 支持集成多种错误处理机制,如 Hystrix 和 Ribbon,可以增强系统的健壮性和稳定性。 - **序列化支持**:Feign 支持多种序列化库(Jackson、Gson 等),选择合适的序列化库可以帮助提高性能或兼容性。 - **日志记录**:通过配置日志级别和内容,可以在请求过程中获取更多详细信息,有助于调试和监控。 ### 相关问题: 1. **如何自定义 Feign 的默认超时时间和连接时间?** 2. **如何集成 Feign 与其他微服务框架一起使用,比如 Spring Cloud?** 3. **在哪些场景下 Feign 比其他HTTP客户端更合适?**
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值