openFeign外部依赖的FeignClient对象注入

概述        

       最近在开发项目时引用了外部的接口,接口我是以feign的方式实现的,在moudleA中。但是在其他模块moudleB引用并使用了moudleA的Feign接口。所以就必须要将moudleA的@FeignClient注释的接口加入MoudleB的容器中。一下讲述一下实现方式。

假设moudleA有以下接口:

@FeignClient(name = TestCommon.SERVICE_NAME, path = TestCommon.SERVICE_BASE_BATH)
public interface TestClient{

    @GetMapping("/get")
    BaseResult<String> get(@RequestParam("id") String id);
}

第一种:

在moudleB的启动类中加入 @EnableFeignClients(basePackages = {"包路径a.*","包路径2.*"})注解:

@EnableFeignClients(basePackages = {"包路径a.*","包路径2.*"})
@SpringBootApplication
public class ServerTestApp {
    public static void main( String[] args){
        SpringApplication app = new SpringApplication(ServerTestApp .class);
        app.run(args);
    }
}

第二种;

        以上的方式都需要moudleB主动去修改自己的代码。下面这种是,moudleA自己将类注入到是容器中。

@FeignClient(name = "testClient", path = TestCommon.SERVICE_BASE_BATH)
public interface TestClient{

    @GetMapping("/get")
    BaseResult<String> get(@RequestParam("id") String id);
}

这里的name需要配置成唯一的,不再代表注册中心的服务标识。 

@Configuration
public class FeignClientBeanConfiguration {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean(name = "testClient")
    public TestClient testClient(){
        FeignClientBuilder builder = new FeignClientBuilder(applicationContext);
        FeignClient annotation = TestClient.class.getAnnotation(FeignClient.class);
        return builder.forType(TestClient.class, annotation.name()).url(annotation.url()).build();
    }
}

 这种方法需要在spring扫描时,要将FeignClientBeanConfiguration 所在的包扫描到,这个可以在,@SpringBootApplication 和@ComponentScan配置的。这样就可以将TestClient注入mouldeB的容器中,moudleB可以直接使用@Autowired注解获取。

@Autowired
private TestClient;

但是这个方法有一个问题,如果mouldeB自己配置@EnableFeignClients注解,且能扫描到TestClient这就会报错:

Description:

The bean 'AuthFeign.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

 所以我们可以按照以上的配置参数。或者使用@ConditionalOnMissingBean(已有的不再注入)和@Primary注解(指定以哪个为主)

@Configuration
public class FeignClientBeanConfiguration {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean(name = "testClient")
    @ConditionalOnMissingBean(TestClient.class)
    public TestClient testClient(){
        FeignClientBuilder builder = new FeignClientBuilder(applicationContext);
        FeignClient annotation = TestClient.class.getAnnotation(FeignClient.class);
        return builder.forType(TestClient.class, annotation.name()).url(annotation.url()).build();
    }
}

还有一个问题是,使用这种方式,若我们在这个@FeignClient里配置了configuration参数,这时候这个配置是不生效的。

第三种:

        我们还可以构建统一的代理,利用spring的实现创建feign的实现,每次只要传入我们想要的feign的类就能获取到对应的实现。

@Component
public class DynamicFeignClient<T> {

    private FeignClientBuilder feignClientBuilder;


    public DynamicFeignClient(@Autowired ApplicationContext appContext) {
        this.feignClientBuilder = new FeignClientBuilder(appContext);
    }

    //构建查询实现  FeignClientFactoryBean  ,指定要调用的url参数
    public T getFeignClient(final Class<T> targetCls, String url) {
        boolean hasFeignClientAnnotation = AnnotatedElementUtils.hasAnnotation(targetCls, CoreManageFeignClientAnnotation.class);
        boolean feignClientAnnotation = AnnotatedElementUtils.hasAnnotation(targetCls, FeignClient.class);

        if(hasFeignClientAnnotation && feignClientAnnotation && StringUtils.isNotEmpty(url)) {

            FeignClient feignClient = AnnotatedElementUtils.findMergedAnnotation(targetCls, FeignClient.class);
            String serviceId = feignClient.name();
            String path =  feignClient.path();
            Class<? extends T> fallback = (Class<? extends T>)feignClient.fallback();
            Class<? extends FallbackFactory<? extends T>> fallbackFactory = (Class<? extends FallbackFactory<? extends T>>)feignClient.fallbackFactory();

            return this.feignClientBuilder.forType(targetCls, serviceId)
                    .url(url).path(path)
                    .fallback(fallback).fallbackFactory(fallbackFactory)
                    .build();
        } else {
            return SpringContextUtils.getBean(targetCls);
        }
    }

//构建查询实现  FeignClientFactoryBean,这个暂未尝试过
    public T getFeignClient(final Class<T> targetCls) {
        boolean hasFeignClientAnnotation = AnnotatedElementUtils.hasAnnotation(targetCls, CoreManageFeignClientAnnotation.class);
        boolean feignClientAnnotation = AnnotatedElementUtils.hasAnnotation(targetCls, FeignClient.class);

        if(hasFeignClientAnnotation && feignClientAnnotation) {

            FeignClient feignClient = AnnotatedElementUtils.findMergedAnnotation(targetCls, FeignClient.class);
            String serviceId = feignClient.name();
            String path =  feignClient.path();
            String url  = feignClient.url();
            Class<? extends T> fallback = (Class<? extends T>)feignClient.fallback();
            Class<? extends FallbackFactory<? extends T>> fallbackFactory = (Class<? extends FallbackFactory<? extends T>>)feignClient.fallbackFactory();

            return this.feignClientBuilder.forType(targetCls, serviceId)
                    .url(url).path(path)
                    .fallback(fallback).fallbackFactory(fallbackFactory)
                    .build();
        } else {
            return SpringContextUtils.getBean(targetCls);
        }
    }
}

        使用这种方式,若我们在这个@FeignClient里配置了configuration参数,这时候这个配置是不生效的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值