您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Spring注解之@Import注解怎么使用”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
在Spring中@Import使用得比較頻繁,它得作用是導(dǎo)入bean,具體的導(dǎo)入方式有多種,特別在SpringBoot項(xiàng)目中,很多地方都使用到了@Import注解,特別對(duì)于一些和SpringBoot整合的組件,其實(shí)現(xiàn)都大量使用了@Import,例如使用Feign集成SpringBoot時(shí)會(huì)加上注解@EnableFeignClients,使用Dubbo時(shí)會(huì)使用@EnableDubbo等,這些注解里面都使用了@Import注解來(lái)注冊(cè)一些bean。
@Import導(dǎo)入bean有三種方式,分別是導(dǎo)入普通類
,實(shí)現(xiàn)ImportSelector
接口的類,實(shí)現(xiàn)ImportBeanDefinitionRegistrar
接口的類。
在開(kāi)放過(guò)程中,盡量保持類不要太過(guò)于龐大,類過(guò)于龐大的話會(huì)變得臃腫復(fù)雜,不好維護(hù),一個(gè)配置類中需要配置很多bean,且邏輯實(shí)現(xiàn)也比較復(fù)雜,代碼量大,如果全部都放在同一個(gè)配置類中,這顯然不太理智,這時(shí)候我們可以將每個(gè)bean單獨(dú)拿出來(lái)放到一個(gè)類里面,然后使用@Import注解導(dǎo)入,如下代碼所示。
定義一個(gè)bean
@Data public class UserBean { private String username; private String sex; }
導(dǎo)入bean
@Configuration @Import(value = {UserBean.class}) //注入普通Bean public class ImportConfiguration { }
從上面可以看出只需要在配置類上面使用@Import注解導(dǎo)入對(duì)應(yīng)Java Bean,然后這個(gè)bean就能注冊(cè)進(jìn)IOC容器中。
ImportSelector是一個(gè)接口,可以通過(guò)實(shí)現(xiàn)它來(lái)完成bean的注冊(cè),它只有一個(gè)selectImports()
方法,它會(huì)返回一個(gè)bean的名稱數(shù)組,這個(gè)數(shù)組中的bean名稱就會(huì)被注冊(cè)進(jìn)IOC容器中。
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{UserBean.class.getName()}; } }
使用ImportBeanDefinitionRegistrar也可以注冊(cè)bean,它會(huì)傳入BeanDefinitionRegistry接口,然后進(jìn)可以注冊(cè)bean,這里注冊(cè)的是bean的元信息BeanDefinition。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { String name = UserBean.class.getName(); BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(UserBean.class); builder.addPropertyValue("sex","男"); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); registry.registerBeanDefinition(name, beanDefinition); } }
spring容器啟動(dòng)后,會(huì)在ConfigurationClassParser
解析類中解析@Import注解,解析出需要注冊(cè)的bean,下面就是最關(guān)鍵的代碼,通過(guò)調(diào)用processImports方法,然后解析出對(duì)應(yīng)的bean,可以看出有幾個(gè)判斷,分別判斷是否是ImportSelector類型,ImportBeanDefinitionRegistrar類型,如果都不是,則證明是直接導(dǎo)入普通java類,如果是普通java類和ImportSelector類型,那么就會(huì)將要注冊(cè)的bean加入一個(gè)Map集合configurationClasses中,后續(xù)會(huì)將它進(jìn)行注冊(cè),如果是ImportBeanDefinitionRegistrar類型,那么會(huì)將其加入一個(gè)Map集合importBeanDefinitionRegistrars中,后續(xù)在擴(kuò)展點(diǎn)會(huì)對(duì)它進(jìn)行再次處理。
private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { if (candidate.isAssignable(ImportSelector.class)) { Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } if (selector instanceof DeferredImportSelector deferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, deferredImportSelector); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<ConfigurationClassParser.SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } }
經(jīng)過(guò)上面解析后,Spring會(huì)注冊(cè)Bean的元信息,會(huì)通過(guò)configClass.isImported()
判斷bean是否是通過(guò)@Import方式導(dǎo)入的普通bean或者ImportSelector類型的導(dǎo)入的bean,如果是,則執(zhí)行registerBeanDefinitionForImportedConfigurationClass
,里面主要就是組裝成BeanDefinition,然后注冊(cè)進(jìn)BeanFactory。
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
如果是通過(guò)ImportBeanDefinitionRegistrar方式,則會(huì)調(diào)用loadBeanDefinitionsFromRegistrars,里面會(huì)循環(huán)去執(zhí)行我們自定義的ImportBeanDefinitionRegistrar,然后進(jìn)行bean的元信息注冊(cè)。
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) { registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator)); }
從上面的源碼解析中,我們看出通過(guò)@Import直接導(dǎo)入普通的java類和導(dǎo)入實(shí)現(xiàn)了ImportSelector接口的類是直接注冊(cè)進(jìn)BeanFactory,這兩者本質(zhì)是一樣的,而通過(guò)實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口方式的類則需要去實(shí)現(xiàn)我們自定義的注冊(cè)bean元信息的邏輯。
“Spring注解之@Import注解怎么使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。