1.@Import
注解在springBoot中間接的廣泛應(yīng)用
?在springboot中并沒有直接顯式的使用@Import
標(biāo)簽啦鸣,而是通過@Import
標(biāo)簽來間接的提供了很多自動配置的注解。比如@EnableAutoConfiguration
来氧,@EnableConfigurationProperties
等诫给。這些標(biāo)簽的實現(xiàn)都是通過使用@Import
標(biāo)簽來完成的。
......
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
......
}
......
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {
......
}
?可以發(fā)現(xiàn)都是通過@Import
來完成的啦扬。
2.spring中的@Import
注解
2.1@Import
注解的作用
?@Import
標(biāo)簽可以導(dǎo)入一個或者多個組件類中狂,通常是@Configuration
注入的bean。提供了與xml中<import/>
標(biāo)簽類型的功能扑毡,能夠?qū)?code>@Configuration類胃榕。
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
?導(dǎo)入的類可以是@Configuration
類型的配置類,實現(xiàn)了ImportSelector
接口的類瞄摊,實現(xiàn)了ImportBeanDefinitionRegistrar
的類或者常規(guī)的組件類勋又。
2.2@Import
的解析前的處理
?@Import
處理的位置其實跟@Conditional
注解都在同一個類中苦掘,處理的時機也是一樣的。這里可以去看看@Conditional
注解解析的邏輯楔壤。
2.2.1 容器的刷新時候的準(zhǔn)備
?在容器刷新方法就定義在AbstractApplicationContext
類的refresh
方法中鹤啡。在這個里面會有解析注冊以及實例話bean和其他的步驟,我們要看的就是解析跟注冊步驟挺邀。
public void refresh() throws BeansException, IllegalStateException {
......
invokeBeanFactoryPostProcessors(beanFactory);
}
?在invokeBeanFactoryPostProcessors
方法中會實例化所有的BeanFactoryPostProcessor
類型的類并調(diào)用實現(xiàn)的postProcessBeanFactory
方法揉忘。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
......
}
2.2.2 PostProcessorRegistrationDelegate
處理BeanDefinitionRegistry
以及BeanFactoryPostProcessor
?這里直接進入到invokeBeanFactoryPostProcessors
方法。會有兩種處理方式:
- 當(dāng)前的
beanFactory
是BeanDefinitionRegistry
類型的
(1) 先處理beanFactory
端铛,然后按照是否實現(xiàn)了PriorityOrdered
,Ordered
以及兩個都沒有實現(xiàn)的順序來處理BeanDefinitionRegistryPostProcessor
接口的實現(xiàn)類泣矛。
(2)處理實現(xiàn)了BeanFactoryPostProcessor
接口的子類依次調(diào)用實現(xiàn)的postProcessBeanFactory
方法 - 當(dāng)前的
beanFactory
不是BeanDefinitionRegistry
類型的,則直接處理實現(xiàn)了BeanFactoryPostProcessor
接口的子類依次調(diào)用實現(xiàn)的postProcessBeanFactory
方法
?其中會處理@Import
標(biāo)簽的ConfigurationClassPostProcessor
實現(xiàn)類BeanDefinitionRegistryPostProcessor
接口跟PriorityOrdered
接口間接實現(xiàn)了BeanFactoryPostProcessor
接口因此無論怎么樣都會被調(diào)用的禾蚕。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
//如果當(dāng)前的beanFactory是BeanDefinitionRegistry的您朽,則需要將已經(jīng)存在的beanDefinition進行注冊
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//保存注冊bean的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//迭代beanFactoryPostProcessors如果是BeanDefinitionRegistryPostProcessor子類則加入到registryProcessors集合中
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
//處理beanFactory中的beanDefinitionNames
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
//先處理同時實現(xiàn)了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor的實現(xiàn)類
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//如果當(dāng)前的BeanDefinitionRegistryPostProcessor類的實現(xiàn)類也實現(xiàn)了PriorityOrdered類,則加入當(dāng)當(dāng)前需要注冊的BeanDefinitionRegistryPostProcessor集合
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//進行排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//加入到registryProcessors集合
registryProcessors.addAll(currentRegistryProcessors);
//調(diào)用實現(xiàn)了BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
......
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
}
2.2.3 ConfigurationClassPostProcessor
的processConfigBeanDefinitions
跟processConfigBeanDefinitions
解析bean
?上面提到了ConfigurationClassPostProcessor
無論怎么樣都會被調(diào)用换淆。這里先看看實現(xiàn)的postProcessBeanDefinitionRegistry
方法跟postProcessBeanFactory
的共同點哗总。
//在refresh方法中最先被調(diào)用
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
//給當(dāng)前的BeanDefinitionRegistry類型的beanFactory設(shè)置一個全局hash值,避免重復(fù)處理
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
//加入到已經(jīng)處理的PostProcessed集合中
this.registriesPostProcessed.add(registryId);
//進行處理
processConfigBeanDefinitions(registry);
}
/**
* Prepare the Configuration classes for servicing bean requests at runtime by replacing them with CGLIB-enhanced subclasses.
*/
//在refresh方法中第二被調(diào)用
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//給當(dāng)前的ConfigurableListableBeanFactory類型的beanFactory設(shè)置一個全局hash值倍试,避免重復(fù)處理
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
//加入到已經(jīng)處理的集合中
this.factoriesPostProcessed.add(factoryId);
//如果當(dāng)前的beanFactory不在registriesPostProcessed中則進行處理
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//將beanFactory中用Configuration注解配置的bean進行動態(tài)加強
enhanceConfigurationClasses(beanFactory);
//增加一個ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
?發(fā)現(xiàn)一個共同點就是讯屈,如果沒有解析過的beanFactory
進來都會調(diào)用processConfigBeanDefinitions
方法來處理Configuration
類。在這個方法中有兩個解析的位置县习。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//循環(huán)處理知道所有的bean都處理完涮母,包含bean內(nèi)部定義的bean
do {
//第一個解析的位置,這里是解析能夠直接獲取的候選配置bean躁愿∨驯荆可能是Component,ComponentScan彤钟,Import来候,ImportResource或者有Bean注解的bean
parser.parse(candidates);
parser.validate();
//獲取上面封裝已經(jīng)解析過的配置bean的ConfigurationClass集合
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
//移除前面已經(jīng)處理過的
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//第二個解析的位置,這里是加載configurationClasse中內(nèi)部可能存在配置bean逸雹,比如方法上加了@Bean或者@Configuration標(biāo)簽的bean
this.reader.loadBeanDefinitions(configClasses);
......
}
......
}
?兩個解析的位置分別是:
- 第一個位置是
ConfigurationClassParser
類的parse
方法营搅,解析能夠直接從beanFactory
中獲取的候選bean。 - 第二個是
ConfigurationClassBeanDefinitionReader
的loadBeanDefinitions
方法梆砸,解析從直接獲取的候選bean中內(nèi)部定義的bean剧防。
2.2.4 ConfigurationClassParser
的解析過程
?ConfigurationClassParser
的parse
有很多重載的方法,但是內(nèi)部邏輯都是調(diào)用的processConfigurationClass
方法辫樱。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
//解析bean
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//處理DeferredImportSelector類型的實現(xiàn)類
this.deferredImportSelectorHandler.process();
}
protected final void parse(@Nullable String className, String beanName) throws IOException {
......
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
?從上面可以看出來峭拘,主要要看的邏輯還是在processConfigurationClass
方法中。這里還需要注意一點就是在最上面的parse
方法最后有一個邏輯this.deferredImportSelectorHandler.process()
這個邏輯是處理@Import
注解中指定的引入類是DeferredImportSelectorHandler
子類的情況的。
?進入到processConfigurationClass
方法鸡挠,關(guān)于這個方法在@Conditional
注解解析的邏輯這個里面說到過辉饱。這里只需要關(guān)注內(nèi)部的doProcessConfigurationClass
方法的邏輯。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//檢查當(dāng)前解析的配置bean是否包含Conditional注解拣展,如果不包含則不需要跳過
// 如果包含了則進行match方法得到匹配結(jié)果彭沼,如果是符合的并且設(shè)置的配置解析策略是解析階段不需要調(diào)過
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//從緩存中嘗試獲取當(dāng)前配置bean解析之后的ConfigurationClass對象
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
//檢查當(dāng)前這個配置bean是通過@Import標(biāo)簽引入的還是自動注入到另外一個配置類bean里面的
if (configClass.isImported()) {
//如果是通過@Import標(biāo)簽引入則將當(dāng)前解析的配置bean加入到已經(jīng)存在的解析過的bean的用來保存通過@Import標(biāo)簽引入的bean的集合中
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
//將當(dāng)前解析的配置bean代替之前的
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
//遞歸獲取原始的配置類信息然后封裝為SourceClass
SourceClass sourceClass = asSourceClass(configClass);
do {
//處理configClass
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
//保存到configurationClasses中
this.configurationClasses.put(configClass, configClass);
}
?在doProcessConfigurationClass
方法中有很多標(biāo)簽的處理邏輯,比如@Component
备埃,@PropertySources
姓惑,@ComponentScans
等。對于@Import
注解的處理方式按脚,封裝在了另外的一個方法processImports
里面于毙。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
.......
processImports(configClass, sourceClass, getImports(sourceClass), true);
......
}
2.3 @Import
注解的解析
2.3.1 processImports
方法
?已經(jīng)知道@Import
注解在那個方法里面進行解析了。先看看對應(yīng)的方法參數(shù)的含義辅搬。
參數(shù) | 含義 |
---|---|
ConfigurationClass configClass | 當(dāng)前需要解析的Configuration類 |
SourceClass currentSourceClass | 類的源數(shù)據(jù)封裝對象 |
Collection<SourceClass> importCandidates | Configuration類引入的其他類唯沮,以及其他類中引入的別的類,比如A引入B堪遂,B引入C介蛉,C引入D。那么這個就包含了B溶褪,C币旧,D |
boolean checkForCircularImports | 是否檢查循環(huán)引入 |
?現(xiàn)在對方法內(nèi)部進行分析
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
//檢查包含有Import注解的集合是不是空的,空的則表示沒有
if (importCandidates.isEmpty()) {
return;
}
//檢查是否存在循環(huán)引入猿妈,通過deque的方式來檢查
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
//將當(dāng)前bean放到importStack中吹菱,用于檢查循環(huán)引入
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
//import指定的Bean是ImportSelector類型
if (candidate.isAssignable(ImportSelector.class)) {
//實例化指定的ImportSelector子類
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
//如果是ImportSelector的子類DeferredImportSelector的子類則按照DeferredImportSelectorHandler邏輯進行處理
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {//如果不是則獲取指定的需要引入的class的ClassNames
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
//根據(jù)ClassNames獲取并封裝成一個SourceClass
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
//繼續(xù)調(diào)用processImports處理
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}//如果是ImportBeanDefinitionRegistrar的子類
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
//如果對應(yīng)的ImportBeanDefinitionRegistrar子類對象,并放到configClass于游,這個是用來注冊額外的bean的
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {//不是上面任何類的子類就可以進行處理了,將指定的需要引入的bean轉(zhuǎn)化為ConfigurationClass垫言,然后到processConfigurationClass方法中處理
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
?主要的步驟如下:
- 檢查解析出來的Import注解集合是不是空的贰剥,空的則不處理,直接返回
- 如果設(shè)置了需要檢查循環(huán)依賴筷频,則進行循環(huán)依賴的檢查蚌成,不需要則跳過,進入3步驟
- 進行處理
(1) 將當(dāng)前bean放到importStack
中凛捏,用于檢查循環(huán)引入
(2)循環(huán)處理以下情況
??1)如果是ImportSelector
類型的子類担忧。先實例化這個類,然后檢查這個類是不是DeferredImportSelector
子類坯癣,是的則調(diào)用ConfigurationClassParser
的內(nèi)部類DeferredImportSelectorHandler
的handle
方法處理瓶盛。如果不是DeferredImportSelector
子類則繼續(xù)調(diào)用processImports
方法處理。按照步驟1從頭開始。
??2)如果是ImportBeanDefinitionRegistrar
類型的子類惩猫,則實例化這個類芝硬,然后放到當(dāng)前解析的bean的importBeanDefinitionRegistrars
屬性中,后面注冊bean時候調(diào)用轧房。
??3)沒有實現(xiàn)以上任何接口拌阴,則將當(dāng)前的被引入的bean加入到這個bean的importedBy
屬性中,然后調(diào)用processConfigurationClass
方法奶镶。
?對上面的信息進行總結(jié)迟赃。這個方法作用就是解析時候?qū)⒈挥?code>@Import注解引入的bean加入到使用@Import
注解標(biāo)簽的bean的importedBy
中后面進行解析時候用,還有就是后面注冊bean的時候可能也會調(diào)用實現(xiàn)了ImportBeanDefinitionRegistrar
類型的子類厂镇。
2.3.2 processConfigurationClass
方法處理configClass
?上面processImports
方法調(diào)用之后最后都會返回到processConfigurationClass
纤壁。這里介紹以下這個方法的作用。這個方法會對ConfigurationClass
對象(這個對象封裝了貼了@Configuration
或者@Bean
注解的對象的信息)進行解析剪撬,解析上面的注解摄乒。就我們上面提到的@Component
,@PropertySources
残黑,@ComponentScans
等馍佑。最后保存起來,后面實例化的時候會用到(后面實例化的時候使用的是CGLIB的方式實例化的)梨水,跟其他的bean不一樣拭荤。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
......
do {
//處理configClass
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
//保存到configurationClasses中
this.configurationClasses.put(configClass, configClass);
}
?到這里@Import
注解的解析基本就完了。剩下的就是介紹ImportSelector
疫诽,ImportBeanDefinitionRegistrar
以及DeferredImportSelector
之間的區(qū)別了舅世。下篇文章解析。
3.ImportSelector
奇徒,ImportBeanDefinitionRegistrar
以及DeferredImportSelector
?在上面的processImports
方法中已經(jīng)講解了對所有的@Import
注解中value
值為不同指的情況進行解析俗批。有以下的情況:
-
ImportSelector
接口的實現(xiàn)類 -
DeferredImportSelector
接口的實現(xiàn)類 -
ImportBeanDefinitionRegistrar
接口的實現(xiàn)類 - 非以上3中接口的實現(xiàn)類铸题,也就是普通的類
?這里主要講解1到3這三個接口類的區(qū)別。
3.1 ImportSelector
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
?ImportSelector
接口作用將方法返回的字符串?dāng)?shù)組作為bean注入到容器中,注意這里的字符串需要是對象的全路徑名稱比如A.class.getName()
這種速客。后面會講spring的擴展的時候會使用的并村。
3.2 ImportBeanDefinitionRegistrar
?ImportBeanDefinitionRegistrar
這個接口作用是苍柏,用戶可以實現(xiàn)了之后來自定義來注冊需要注冊的bean画切。可以設(shè)置自定義的BeanNameGenerator
bean名稱生成規(guī)則长踊。
public interface ImportBeanDefinitionRegistrar {
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
3.3 DeferredImportSelector
?ImportBeanDefinitionRegistrar
是ImportSelector
的子接口功舀,在4.0版本加入的。在這個類里面添加分組的功能身弊,能夠?qū)⒍鄠€DeferredImportSelector
進行分組辟汰。同一個組內(nèi)的ImportBeanDefinitionRegistrar
能夠通過實現(xiàn)@Order
注解去實現(xiàn)排序列敲。在調(diào)用的時候處理的時候會先按照序號進行排序,然后依次調(diào)用對應(yīng)實現(xiàn)的 ImportSelector
接口的selectImports
方法莉擒。
?還有一點就是DeferredImportSelector
的調(diào)用邏輯在酿炸,所有的@Configuration
已經(jīng)解析了之后在調(diào)用的。這點可以在2.2.4 ConfigurationClassParser的解析過程
代碼中看出來涨冀。
public interface DeferredImportSelector extends ImportSelector {
default Class<? extends Group> getImportGroup() {
return null;
}
interface Group {
......
}
?這里將區(qū)別列舉出來
類 | 作用 |
---|---|
ImportSelector |
將方法返回的字符串?dāng)?shù)組作為bean注入到容器中 |
ImportBeanDefinitionRegistrar |
自定義來注冊bean |
DeferredImportSelector |
跟ImportSelector 差不多只不過多了分組的功能填硕,處理在@Configuration 類型bean解析之后 |