淺析Feign代理bean 注入原理
大家不知道有沒有好奇過各種spring框架中的神奇功能是怎麼實現的,例如Feign 的介面,和Jpa 的介面,Spring 是如何驅動實現的呢。下面我來分析一下
在瞭解FeignClient 註解中發現,FeignClient 註解的介面都是Proxy 類。那到底是如何生成的呢?
spring在注入bean的時候,會根據容器中bean 的型別或者name 來匹配bean 的注入,
但是interface型別的介面是無法作為bean 生成的,所以必須有一個機制來生成實現了對應介面的類,然後注入到Ioc容器中。
FeignClient 中使用到的是BeanFactory 來生成對應的bean實體,下面來看下Feign中的原始碼:
首先我們跟蹤@EnableFeignClients 註解, 裡面可以看到有一個FeignClientsRegistrar 配置類
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { .... }
這個類實現了ImportBeanDefinitionRegistrar 介面,這個介面有什麼特別呢?在spring中,如果bean實現了這個介面,那麼這個bean會被對待為配置Bean ,而不作為注入的bean生成。
繼續跟蹤程式碼:
@Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { registerDefaultConfiguration(metadata, registry); registerFeignClients(metadata, registry); }
這個就是Bean 生成的入口,一直跟蹤程式碼下面,會有個方法:registerFeignClient ,這裡可以看到一個很關鍵的地方
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { ... BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); ... }
這裡是獲得bean的工廠類,然後根據工廠類來生成proxy。
跟蹤到FeignClientFactoryBean ,可以發現工廠類實現類FactoryBean<T>介面
這裡重點關注getObject()方法,Srping Ioc容器就是根據這個方法來獲取對應的Bean,那麼還有一個問題,前面剛剛提到,spring是可以根據name 或者型別來注入bean的,這裡應該還需要指定對應的type 才能讓spring決定注入的bean,方法就是 FactoryBean 介面的Class<?> getObjectType()
而FeignClientFactoryBean中實現的方法如下:
@Override public Class<?> getObjectType() { return this.type; }
從配置中獲取到type,這裡我們往回看,可以看到:
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { String className = annotationMetadata.getClassName(); BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); ... definition.addPropertyValue("type", className); ... definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
這裡獲取的就是@FeignClient 註解上的介面型別,所以spring就能根據這個返回生成的代理物件注入到介面當中。對於想了解具體的代理生成方式的同學,可以看getObject中的詳細實現。
這裡就分享得差不多了,有問題請留言。筆者技術水平有限,如有出錯,歡迎指出,謝謝。
技術交流,可以加微信:youliaodao_zc