日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

(转)Spring Boot通过ImportBeanDefinitionRegistrar动态注入Bean

發布時間:2023/12/3 javascript 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (转)Spring Boot通过ImportBeanDefinitionRegistrar动态注入Bean 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:

Spring Boot通過ImportBeanDefinitionRegistrar動態注入Bean - 掘金在閱讀SpringBoot源碼時,看到SpringBoot中大量使用ImportBeanDefinitionRegistrar來實現Bean的動態注入。它是Spring中一個強大的擴展接口。本篇文章來https://juejin.cn/post/6844903971119693837

【README】

實現 ImportBeanDefinitionRegistrar 動態注入Bean的應用場景

  • 1.springboot封裝多個同類型客戶端的情況,如多個rabbitmq生產者客戶端(多個集群),多個kafka生產者客戶端(多個集群) 等等;springboot提供了對應的rabbittemplate,kafkatemplate等,但也需要多個連接;
  • 2.該接口或該功能對于基于 springboot封裝底層后臺框架非常有用;

在閱讀Spring Boot源碼時,看到Spring Boot中大量使用ImportBeanDefinitionRegistrar來實現Bean的動態注入。它是Spring中一個強大的擴展接口。本篇文章來講講它相關使用。

Spring Boot中的使用

在Spring Boot 內置容器的相關自動配置中有一個ServletWebServerFactoryAutoConfiguration類。該類的部分代碼如下:

@Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @ConditionalOnClass(ServletRequest.class) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(ServerProperties.class) @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,ServletWebServerFactoryConfiguration.EmbeddedJetty.class,ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration {// .../*** Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via* {@link ImportBeanDefinitionRegistrar} for early registration.*/public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {private ConfigurableListableBeanFactory beanFactory;// 實現BeanFactoryAware的方法,設置BeanFactory@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {if (beanFactory instanceof ConfigurableListableBeanFactory) {this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;}}// 注冊一個WebServerFactoryCustomizerBeanPostProcessor@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {if (this.beanFactory == null) {return;}registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",WebServerFactoryCustomizerBeanPostProcessor.class);registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",ErrorPageRegistrarBeanPostProcessor.class);}// 檢查并注冊Beanprivate void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {// 檢查指定類型的Bean name數組是否存在,如果不存在則創建Bean并注入到容器中if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);beanDefinition.setSynthetic(true);registry.registerBeanDefinition(name, beanDefinition);}}} }

在這個自動配置類中,基本上展示了ImportBeanDefinitionRegistrar最核心的用法。這里該接口主要用來注冊BeanDefinition。

BeanPostProcessorsRegistrar實現了ImportBeanDefinitionRegistrar接口和BeanFactoryAware接口。其中BeanFactoryAware接口的實現是用來暴露Spring的ConfigurableListableBeanFactory對象。

而實現registerBeanDefinitions方法則是用來對Bean的動態注入,這里注入了WebServerFactoryCustomizerBeanPostProcessor和ErrorPageRegistrarBeanPostProcessor。

簡單了解了Spring Boot中的一個使用實例,下面我們總結一下使用方法,并自己實現一個類似的功能。

ImportBeanDefinitionRegistrar使用

Spring官方通過ImportBeanDefinitionRegistrar實現了@Component、@Service等注解的動態注入機制。

很多三方框架集成Spring的時候,都會通過該接口,實現掃描指定的類,然后注冊到spring容器中。 比如Mybatis中的Mapper接口,springCloud中的FeignClient接口,都是通過該接口實現的自定義注冊邏輯。

所有實現了該接口的類的都會被ConfigurationClassPostProcessor處理,ConfigurationClassPostProcessor實現了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中動態注冊的bean是優先于依賴其的bean初始化,也能被aop、validator等機制處理。

基本步驟:

  • 實現ImportBeanDefinitionRegistrar接口;
  • 通過registerBeanDefinitions實現具體的類初始化;
  • 在@Configuration注解的配置類上使用@Import導入實現類;

簡單示例

這里實現一個非常簡單的操作,自定義一個@Mapper注解(并非Mybatis中的Mapper實現),實現類似@Component的功能,添加了@Mapper注解的類會被自動加載到spring容器中。

首先創建@Mapper注解。

@Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) public @interface Mapper { }

創建UserMapper類,用于使用@Mapper注。

@Mapper public class UserMapper { }

定義ImportBeanDefinitionRegistrar的實現類MapperAutoConfigureRegistrar。如果需要獲取Spring中的一些數據,可實現一些Aware接口,這實現了ResourceLoaderAware。

public class MapperAutoConfigureRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {private ResourceLoader resourceLoader;@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {MapperBeanDefinitionScanner scanner = new MapperBeanDefinitionScanner(registry, false);scanner.setResourceLoader(resourceLoader);scanner.registerFilters();scanner.addIncludeFilter(new AnnotationTypeFilter(Mapper.class));scanner.doScan("com.secbro2.learn.mapper");}@Overridepublic void setResourceLoader(ResourceLoader resourceLoader) {this.resourceLoader = resourceLoader;} }

在上面代碼中,通過ResourceLoaderAware接口的setResourceLoader方法獲得到了ResourceLoader對象。

在registerBeanDefinitions方法中,借助ClassPathBeanDefinitionScanner類的實現類來掃描獲取需要注冊的Bean。

MapperBeanDefinitionScanner的實現如下:

public class MapperBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {public MapperBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {super(registry, useDefaultFilters);}protected void registerFilters() {addIncludeFilter(new AnnotationTypeFilter(Mapper.class));}@Overrideprotected Set<BeanDefinitionHolder> doScan(String... basePackages) {return super.doScan(basePackages);} }

MapperBeanDefinitionScanner繼承子ClassPathBeanDefinitionScanner,掃描被@Mapper的注解的類。

在MapperBeanDefinitionScanner中指定了addIncludeFilter方法的參數為包含Mapper的AnnotationTypeFilter。

當然也可以通過excludeFilters指定不加載的類型。這兩個方法由它們的父類ClassPathScanningCandidateComponentProvider提供的。

完成了上面的定義,則進行最后一步引入操作了。創建一個自動配置類MapperAutoConfig,并通過@Import引入自定義的Registrar。


?

@Configuration @Import(MapperAutoConfigureRegistrar.class) public class MapperAutoConfig { }

至此,整個代碼的功能已經編寫完成,下面寫一個單元測試。

@RunWith(SpringRunner.class) @SpringBootTest public class MapperAutoConfigureRegistrarTest {@AutowiredUserMapper userMapper;@Testpublic void contextLoads() {System.out.println(userMapper.getClass());} }

執行單元測試代碼,會發現打印如下日志:

class com.secbro2.learn.mapper.UserMapper

說明UserMapper已經被實例化成功,并注入Spring容器當中。

小結

當然,這里的UserMapper并不接口,這里的實現也并不是Mybatis中的實現形式。只是為了演示該功能的簡單示例。需要注意的是文中提到了兩種實現的實例,第一種是Spring Boot中的實現,第二種是我們的Mapper實例。展現了兩種不同方法的注冊的操作,但整個使用流程是一致的,讀者注意仔細品味,并在此基礎上進行拓展更復雜的功能。

原文鏈接:《Spring Boot通過ImportBeanDefinitionRegistrar動態注入Bean》


?

總結

以上是生活随笔為你收集整理的(转)Spring Boot通过ImportBeanDefinitionRegistrar动态注入Bean的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。