计算机系统应用教程网站

网站首页 > 技术文章 正文

spring源码之ImportSelector、Import、ImportResource原理分析

btikc 2024-09-16 13:02:46 技术文章 23 ℃ 0 评论

1. @importSelector定义:

/**
 * Interface to be implemented by types that determine which @{@link Configuration}
 * class(es) should be imported based on a given selection criteria, usually one or more
 * annotation attributes.
 *
 * <p>An {@link ImportSelector} may implement any of the following
 * {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective
 * methods will be called prior to {@link #selectImports}:
 * <ul>
 * <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
 * <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li>
 * <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li>
 * <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li>
 * </ul>
 *
 * <p>ImportSelectors are usually processed in the same way as regular {@code @Import}
 * annotations, however, it is also possible to defer selection of imports until all
 * {@code @Configuration} classes have been processed (see {@link DeferredImportSelector}
 * for details).
 *
 * @author Chris Beams
 * @since 3.1
 * @see DeferredImportSelector
 * @see Import
 * @see ImportBeanDefinitionRegistrar
 * @see Configuration
 */
public interface ImportSelector {
 /**
 * Select and return the names of which class(es) should be imported based on
 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
 */
 String[] selectImports(AnnotationMetadata importingClassMetadata);
}

实现线索:

具体代码实现:

 private void processDeferredImportSelectors() {
 List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
 this.deferredImportSelectors = null;
 Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
 for (DeferredImportSelectorHolder deferredImport : deferredImports) {
 ConfigurationClass configClass = deferredImport.getConfigurationClass();
 try {
 String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
 processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
 }
 catch (BeanDefinitionStoreException ex) {
 throw ex;
 }
 catch (Throwable ex) {
 throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
 configClass.getMetadata().getClassName() + "]", ex);
 }
 }
 }

2、@Import和@ImportResource的实现如下:

ConfigurationClassParser.java

/**
 * Apply processing and build a complete {@link ConfigurationClass} by reading the
 * annotations, members and methods from the source class. This method can be called
 * multiple times as relevant sources are discovered.
 * @param configClass the configuration class being build
 * @param sourceClass a source class
 * @return the superclass, or {@code null} if none found or previously processed
 */
 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
 // Recursively process any member (nested) classes first
 processMemberClasses(configClass, sourceClass);
 // Process any @PropertySource annotations
 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");
 }
 }
 // Process any @ComponentScan annotations
 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 necessary
 for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
 if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
 parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
 }
 }
 }
 }
 // Process any @Import annotations
 processImports(configClass, sourceClass, getImports(sourceClass), true);
 // Process any @ImportResource annotations
 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);
 }
 }
 // Process individual @Bean methods
 Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
 for (MethodMetadata methodMetadata : beanMethods) {
 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
 }
 // Process default methods on interfaces
 processInterfaces(configClass, sourceClass);
 // Process superclass, if any
 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();
 }
 }
 // No superclass -> processing is complete
 return null;
 }

3.三种方式:

ImportSelector 
ImportBeanDefinitionRegistrar 
Configuration 

ConfigurationClassParser.java

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
 Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
 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) {
 if (candidate.isAssignable(ImportSelector.class)) {
 // Candidate class is an ImportSelector -> delegate to it to determine imports
 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);
 }
 }
 else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
 // Candidate class is an ImportBeanDefinitionRegistrar ->
 // delegate to it to register additional bean definitions
 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 {
 // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
 // process it as an @Configuration class
 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();
 }
 }
 }

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表