Spring源碼解析-@Import注解源碼解析

Spring 3.0之前,創(chuàng)建Bean可以通過(guò)xml配置文件與掃描特定包下面的類來(lái)將類注入到Spring IOC容器內(nèi)。而在Spring 3.0之后提供了JavaConfig的方式,也就是將IOC容器里Bean的元信息以java代碼的方式進(jìn)行描述。我們可以通過(guò)@Configuration與@Bean這兩個(gè)注解配合使用來(lái)將原來(lái)配置在xml文件里的bean通過(guò)java代碼的方式進(jìn)行描述

@Import注解提供了@Bean注解的功能,同時(shí)還有xml配置文件里標(biāo)簽組織多個(gè)分散的xml文件的功能,當(dāng)然在這里是組織多個(gè)分散的@Configuration

先看一下@Import注解的源碼:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    /**

{@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}

or regular component classes to import.

Class<?>[] value();
}

從源碼里可以看出@Import可以配合 Configuration ,ImportSelector, ImportBeanDefinitionRegistrar 來(lái)使用,下面的or表示也可以把Import當(dāng)成普通的Bean使用
@Import只允許放到類上面,不能放到方法上。下面我們來(lái)看具體的使用方式

普通使用方法

這種方式可以直接把類加入到Spring IOC容器

@Configuration
@Import(value={UserServiceImpl.class})
public class Config {

}

但是這種方式有一些問(wèn)題,那就是只能使用類的無(wú)參構(gòu)造方法來(lái)創(chuàng)建bean,對(duì)于有參數(shù)的構(gòu)造方法就無(wú)能為力了

結(jié)合ImportBeanDefinitionRegistrar接口

ImportBeanDefinitionRegistrar接口的源碼如下:

public interface ImportBeanDefinitionRegistrar {
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
     
}

可以看到這個(gè)接口唯一的方法是有兩個(gè)參數(shù)的

AnnotationMetadata:通過(guò)這個(gè)參數(shù)可以拿到類的元數(shù)據(jù)信息
BeanDefinitionRegistry:通過(guò)這個(gè)參數(shù)可以操作IOC容器
我們可以使用一個(gè)類來(lái)實(shí)現(xiàn)這個(gè)接口

public class UserServiceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
  
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder userService = BeanDefinitionBuilder.rootBeanDefinition(UserServiceImpl.class);
        registry.registerBeanDefinition("userService", userService.getBeanDefinition());
    }

}

可以看到我們?cè)谶@個(gè)方法里面做一些特殊操作什么的都是可以的,相比較于普通的方式可是靈活了很多

接著我們?cè)贎Import注解引入的地方只需要修改為引入UserServiceBeanDefinitionRegistrar就可以了

@Configuration
@Import(value={UserServiceBeanDefinitionRegistrar.class})
public class Config {

}

結(jié)合ImportSelector接口

相比較與實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口之后直接操作Bean容器來(lái)說(shuō),使用ImportSelector會(huì)更加優(yōu)雅一些,只需要返回需要注入類的全限定名就可以了

ImportSelector接口的源碼如下:

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata importingClassMetadata);
}
public class UserServiceImportSelect implements ImportSelector{

    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        
       return new String[]{UserServiceImpl.class.getName()};
    }

}
@Configuration()
@Import(value={UserServiceImportSelect.class})
public class Config {

}

相比較三種方式來(lái)說(shuō)可以看到最后這種才是最優(yōu)雅的方式

源碼解析

首先我們就以第三種比較優(yōu)雅的方式出發(fā),使用Call Hierarchy看一下ImportSelector接口的selectImports方法調(diào)用鏈關(guān)系:

看過(guò)之前Spring源碼解析文章的同學(xué)都知道,refresh方法是用來(lái)初始化容器上下文的。跟著這個(gè)調(diào)用鏈走下來(lái)到中間有一個(gè)類是ConfigurationClassPostProcessor,根據(jù)類名我們就可以猜到這個(gè)類應(yīng)該是處理配置類(也就是標(biāo)注@Configuration)的。那么從這開始看吧

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
    String[] candidateNames = registry.getBeanDefinitionNames();

    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
     
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
       //查看是否是配置類
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
    
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }
    //如果沒(méi)有配置類就直接返回
    if (configCandidates.isEmpty()) {
        return;
    }
    
    //對(duì)這些配置類根據(jù)Order排序
    Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
        @Override
        public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
            return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
        }
    });
    
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet && sbr.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
            this.componentScanBeanNameGenerator = generator;
            this.importBeanNameGenerator = generator;
        }
    }
             //創(chuàng)建配置類的解析類
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
    Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
    do {
       //ConfigurationClassParser的parse方法進(jìn)行解析,重點(diǎn)哈
        parser.parse(candidates);
        parser.validate();

        Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
        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());
        }
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);
    
        candidates.clear();
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));
            Set<String> alreadyParsedClasses = new HashSet<String>();
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
            }
            for (String candidateName : newCandidateNames) {
                if (!oldCandidateNames.contains(candidateName)) {
                    BeanDefinition bd = registry.getBeanDefinition(candidateName);
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                            !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                        candidates.add(new BeanDefinitionHolder(bd, candidateName));
                    }
                }
            }
            candidateNames = newCandidateNames;
        }
    }
    while (!candidates.isEmpty());
    
    if (sbr != null) {
        if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
            sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
        }
    }
    
    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }

}

現(xiàn)在該進(jìn)入ConfigurationClassParser類了

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
    

    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            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);
        }
    }
    
    processDeferredImportSelectors();

}

//下面三種方法用于處理不同的BeanDefinition 類型,但最終都是使用的processConfigurationClass方法

protected final void parse(String className, String beanName) throws IOException {
    MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
    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));
}

可以看到配置類可能會(huì)是三種形式的存在,這三種形式的Bean在操作上有著部分不一樣,但是大部分又是一樣,所以Spring用這種模式來(lái)處理。不得不感嘆人家設(shè)計(jì)的真好

接著往下看

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }

    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    //在這里處理Configuration重復(fù)import
    //如果同一個(gè)配置類被處理兩次,兩次都屬于被import的則合并導(dǎo)入類,返回。如果配置類不是被導(dǎo)入的,則移除舊使用新的配置類
    if (existingClass != null) {
        if (configClass.isImported()) {
            if (existingClass.isImported()) {
                existingClass.mergeImportedBy(configClass);
            }
            return;
        }
        else {
            this.configurationClasses.remove(configClass);
            for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) {
                if (configClass.equals(it.next())) {
                    it.remove();
                }
            }
        }
    }
    
    SourceClass sourceClass = asSourceClass(configClass);
    do {
      //接著往下看吧
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);
    
    this.configurationClasses.put(configClass, configClass);

}
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {

    // 處理遞歸類
    processMemberClasses(configClass, sourceClass);
    
    // 處理@PropertySource注解
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), PropertySources.class,
            org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            processPropertySource(propertySource);
        }
        else {
            logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                    "]. Reason: Environment must implement ConfigurableEnvironment");
        }
    }
    
    // 處理 @ComponentScan 注解
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() &&
            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        for (AnnotationAttributes componentScan : componentScans) {
            // The config class is annotated with @ComponentScan -> perform the scan immediately
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // Check the set of scanned definitions for any further config classes and parse recursively if needed
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }
    //處理Import注解,這個(gè)是咱們的菜
    processImports(configClass, sourceClass, getImports(sourceClass), true);
    
    // 處理@ImportResource 注解
    if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
        AnnotationAttributes importResource =
                AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        String[] resources = importResource.getStringArray("locations");
        Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
        for (String resource : resources) {
            String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
            configClass.addImportedResource(resolvedResource, readerClass);
        }
    }
    
    //處理包含@Bean注解的方法
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }
    
    // 處理普通方法
    processInterfaces(configClass, sourceClass);

   


    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
            this.knownSuperclasses.put(superclass, configClass);
            // Superclass found, return its annotation metadata and recurse
            return sourceClass.getSuperClass();
        }
    }
    
    return null;

}

看到這里好像突然發(fā)現(xiàn)了新大陸呀,原來(lái)我們經(jīng)常見的@Bean、@ImportResource 、@Import、@ComponentScan、@PropertySource都是在這里處理的呀

咱們的重點(diǎn)還是放在@Import上,對(duì)其他幾個(gè)注解感興趣的同學(xué)可以自行研究一下

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
        Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

    if (importCandidates.isEmpty()) {
        return;
    }
    
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
        this.importStack.push(configClass);
        try {
            for (SourceClass candidate : importCandidates) {
                //如果實(shí)現(xiàn)了ImportSelector接口
                if (candidate.isAssignable(ImportSelector.class)) {
                    Class<?> candidateClass = candidate.loadClass();
                    ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                    ParserStrategyUtils.invokeAwareMethods(
                            selector, this.environment, this.resourceLoader, this.registry);
                    if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                        this.deferredImportSelectors.add(
                                new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
                    }
                    else {
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                        processImports(configClass, currentSourceClass, importSourceClasses, false);
                    }
                }
                //如果實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    Class<?> candidateClass = candidate.loadClass();
                    ImportBeanDefinitionRegistrar registrar =
                            BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                    ParserStrategyUtils.invokeAwareMethods(
                            registrar, this.environment, this.resourceLoader, this.registry);
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                else {
                     //將import當(dāng)成Configuration來(lái)使用就是我們的第一種應(yīng)用的方式
                    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 源碼閱讀完畢

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容