Spring 3.0以前,建立Bean能夠經過xml配置文件與掃描特定包下面的類來將類注入到Spring IOC容器內。而在Spring 3.0以後提供了JavaConfig的方式,也就是將IOC容器裏Bean的元信息以java代碼的方式進行描述。咱們能夠經過@Configuration與@Bean這兩個註解配合使用來將原來配置在xml文件裏的bean經過java代碼的方式進行描述java
@Import註解提供了@Bean註解的功能,同時還有xml配置文件裏<import>標籤組織多個分散的xml文件的功能,固然在這裏是組織多個分散的@Configurationspring
先看一下@Import註解的源碼:ide
@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
來使用,下面的or表示也能夠把Import當成普通的Bean使用 @Import只容許放到類上面,不能放到方法上。下面咱們來看具體的使用方式 ui
這種方式能夠直接把類加入到Spring IOC容器this
@Configuration @Import(value={UserServiceImpl.class}) public class Config { }
可是這種方式有一些問題,那就是隻能使用類的無參構造方法來建立bean,對於有參數的構造方法就無能爲力了lua
ImportBeanDefinitionRegistrar
接口ImportBeanDefinitionRegistrar
接口的源碼以下:debug
public interface ImportBeanDefinitionRegistrar { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry); }
能夠看到這個接口惟一的方法是有兩個參數的設計
咱們能夠使用一個類來實現這個接口code
public class UserServiceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) { BeanDefinitionBuilder userService = BeanDefinitionBuilder.rootBeanDefinition(UserServiceImpl.class); registry.registerBeanDefinition("userService", userService.getBeanDefinition()); } }
能夠看到咱們在這個方法裏面作一些特殊操做什麼的都是能夠的,相比較於普通的方式但是靈活了不少component
接着咱們在@Import註解引入的地方只須要修改成引入UserServiceBeanDefinitionRegistrar就能夠了
@Configuration @Import(value={UserServiceBeanDefinitionRegistrar.class}) public class Config { }
ImportSelector
接口相比較與實現ImportBeanDefinitionRegistrar
接口以後直接操做Bean容器來講,使用ImportSelector
會更加優雅一些,只須要返回須要注入類的全限定名就能夠了
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 { }
相比較三種方式來講能夠看到最後這種纔是最優雅的方式
首先咱們就以第三種比較優雅的方式出發,使用Call Hierarchy看一下ImportSelector接口的selectImports方法調用鏈關係:
看過以前Spring源碼解析文章的同窗都知道,refresh
方法是用來初始化容器上下文的。跟着這個調用鏈走下來到中間有一個類是ConfigurationClassPostProcessor
,根據類名咱們就能夠猜到這個類應該是處理配置類(也就是標註@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)); } } //若是沒有配置類就直接返回 if (configCandidates.isEmpty()) { return; } //對這些配置類根據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; } } //建立配置類的解析類 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方法進行解析,重點哈 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(); } }
如今該進入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)); }
能夠看到配置類可能會是三種形式的存在,這三種形式的Bean在操做上有着部分不同,可是大部分又是同樣,因此Spring用這種模式來處理。不得不感嘆人家設計的真好
接着往下看
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } ConfigurationClass existingClass = this.configurationClasses.get(configClass); //在這裏處理Configuration重複import //若是同一個配置類被處理兩次,兩次都屬於被import的則合併導入類,返回。若是配置類不是被導入的,則移除舊使用新的配置類 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註解,這個是我們的菜 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; }
看到這裏好像忽然發現了新大陸呀,原來咱們常常見的@Bean
、@ImportResource
、@Import
、@ComponentScan
、@PropertySource
都是在這裏處理的呀
我們的重點仍是放在@Import
上,對其餘幾個註解感興趣的同窗能夠自行研究一下
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) { //若是實現了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); } } //若是實現了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當成Configuration來使用就是咱們的第一種應用的方式 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(); } } }