Spring原始碼分析(三) -- Spring中的BeanFactoryPostProcessor

我很醜發表於2020-04-03

BeanFactoryPostProcessor的定義

@FunctionalInterface
public interface BeanFactoryPostProcessor {
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

複製程式碼
  • 從定義中可以看出BeanFactoryPostProcessor是一個函式式介面
  • BeanFactoryPostProcessor只有一個方法,這個方法返回了一個BeanFactory物件,這個物件可以理解為Spring中的容器。
  • postProcessBeanFactory是在註冊完BeanDefinition後回撥,這個回撥中可以修改BeanDefinition的屬性從而達到修改例項化的Bean

BeanFactoryPostProcessor的擴充類---BeanDefinitionRegistryPostProcessor

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
複製程式碼
  • BeanDefinitionRegistryPostProcessor繼承了BeanFactoryPostProcessor,表示BeanDefinitionRegistryPostProcessor也是一個BeanFactoryPostProcessor
  • BeanDefinitionRegistryPostProcessor是一個介面,新增了一個方法
  • BeanDefinitionRegistryPostProcessor有一個重要的實現類ConfigurationClassPostProcessor

ConfigurationClassPostProcessor 定義

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware
複製程式碼
  • 主要關心實現BeanDefinitionRegistryPostProcessor介面的方法postProcessBeanDefinitionRegistry
postProcessBeanDefinitionRegistry 方法
//這個是一個空殼方法
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    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);
    }
    this.registriesPostProcessed.add(registryId);
	//核心在這,跟進去
    processConfigBeanDefinitions(registry);
}

複製程式碼
processConfigBeanDefinitions 方法
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    //定義一個list存放app 提供的bd(專案當中提供了@Compent)
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    //獲取容器中註冊的所有bd名字
    //7個,系統六個加上一個自己的配置類一共七個
    String[] candidateNames = registry.getBeanDefinitionNames();

    /**
		 * Full的配置類會被代理
		 * Lite的配置類不會被代理
		 */
    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
            ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            //如果BeanDefinition中的configurationClass屬性為full或者lite,則意味著已經處理過了,直接跳過
            //這裡需要結合下面的程式碼才能理解
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        //判斷是否是Configuration類,如果加了Configuration下面的這幾個註解就不再判斷了
        // 還有  add(Component.class.getName());
        //		candidateIndicators.add(ComponentScan.class.getName());
        //		candidateIndicators.add(Import.class.getName());
        //		candidateIndicators.add(ImportResource.class.getName());
        //beanDef == appconfig
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            //BeanDefinitionHolder 也可以看成一個資料結構
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    // Return immediately if no @Configuration classes were found
    if (configCandidates.isEmpty()) {
        return;
    }

    // 排序,根據order,不重要
    // Sort by previously determined @Order value, if applicable
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // Detect any custom bean name generation strategy supplied through the enclosing application context
    SingletonBeanRegistry sbr = null;
    //如果BeanDefinitionRegistry是SingletonBeanRegistry子類的話,
    // 由於我們當前傳入的是DefaultListableBeanFactory,是SingletonBeanRegistry 的子類
    // 因此會將registry強轉為SingletonBeanRegistry
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet) {//是否有自定義的
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
            //SingletonBeanRegistry中有id為 org.springframework.context.annotation.internalConfigurationBeanNameGenerator
            //如果有則利用他的,否則則是spring預設的
            if (generator != null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    // Parse each @Configuration class
    //例項化ConfigurationClassParser 為了解析各個配置類
    ConfigurationClassParser parser = new ConfigurationClassParser(
        this.metadataReaderFactory, this.problemReporter, this.environment,
        this.resourceLoader, this.componentScanBeanNameGenerator, registry);

    //例項化2個set,candidates用於將之前加入的configCandidates進行去重
    //因為可能有多個配置類重複了
    //alreadyParsed用於判斷是否處理過
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
        //candidates中存放的是配置類,這裡解析配置類
        //這裡很重要
        parser.parse(candidates);
        parser.validate();
        //map.keyset
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(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());
        }

        /**
			 * 這裡值得注意的是掃描出來的bean當中可能包含了特殊類
			 * 比如ImportBeanDefinitionRegistrar那麼也在這個方法裡面處理
			 * 但是並不是包含在configClasses當中
			 * configClasses當中主要包含的是importSelector
			 * 因為ImportBeanDefinitionRegistrar在掃描出來的時候已經被新增到一個list當中去了
			 * 上面解析出來的@Bean@Import(三種)都會放入configClasses中
			 */
        //bd 到 map 除卻普通
        //跟進去
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);

        candidates.clear();
        //由於我們這裡進行了掃描,把掃描出來的BeanDefinition註冊給了factory
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
            Set<String> alreadyParsedClasses = new HashSet<>();
            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());

    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        // Clear cache in externally provided MetadataReaderFactory; this is a no-op
        // for a shared cache since it'll be cleared by the ApplicationContext.
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}

複製程式碼
checkConfigurationClassCandidate 方法
//如果傳入的BeanDefinition有Configuration註解,把BeanDefinition的CONFIGURATION_CLASS_ATTRIBUTE屬性設定為full,這個屬性在例項化的時候會生成代理物件
//如果傳入的BeanDefinition有Component、ComponentScan、Import、ImportResource註解,把BeanDefinition的CONFIGURATION_CLASS_ATTRIBUTE屬性設定為lite
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
		String className = beanDef.getBeanClassName();
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}

		AnnotationMetadata metadata;
		// 配置類預設為AnnotatedGenericBeanDefinition物件
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			//如果BeanDefinition 是 AnnotatedBeanDefinition的例項,並且className 和 BeanDefinition中 的後設資料 的類名相同
			// 則直接從BeanDefinition 獲得Metadata
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			//如果BeanDefinition 是 AbstractBeanDefinition的例項,並且beanDef 有 beanClass 屬性存在
			//則例項化StandardAnnotationMetadata
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			metadata = new StandardAnnotationMetadata(beanClass, true);
		}
		else {
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex);
				}
				return false;
			}
		}
		//判斷當前這個bd中存在的類是不是加了@Configruation註解
		//如果存在則spring認為他是一個全註解的類
		if (isFullConfigurationCandidate(metadata)) {
			//如果存在 Configuration 註解,則為BeanDefinition 設定configurationClass屬性為full
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		//判斷是否加了以下註解,摘錄isLiteConfigurationCandidate的原始碼
		//     candidateIndicators.add(Component.class.getName());
		//		candidateIndicators.add(ComponentScan.class.getName());
		//		candidateIndicators.add(Import.class.getName());
		//		candidateIndicators.add(ImportResource.class.getName());
		//如果不存在Configuration註解,spring則認為是一個部分註解類
		else if (isLiteConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}

		// It's a full or lite configuration candidate... Let's determine the order value, if any.
		Integer order = getOrder(metadata);
		if (order != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}

		return true;
	}
複製程式碼
parse 方法
//解析配置類,主要是把Configuration註解類裡面匯入的類解析為對應的BeanDefinition並註冊到容器中去
//注意這個configCandidates裡面只有自己的配置類
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    this.deferredImportSelectors = new LinkedList<>();
    //根據BeanDefinition 的型別 做不同的處理,一般都會呼叫ConfigurationClassParser#parse 進行解析
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            if (bd instanceof AnnotatedBeanDefinition) {
                //解析註解物件,並且把解析出來的bd放到map,但是這裡的bd指的是普通的
                //何謂不普通的呢?比如@Bean 和各種beanFactoryPostProcessor得到的bean不在這裡put
                //但是是這裡解析,只是不put而已
                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);
        }
    }

    //處理延遲載入的importSelect?跳過
    processDeferredImportSelectors();
}

//這個是空殼方法,接著跟進去
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
複製程式碼
processConfigurationClass 方法
//處理配置類
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    //判斷是否應該跳過解析
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }

    // 處理Imported 的情況
    //就是當前這個註解類有沒有被別的類import
    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
        if (configClass.isImported()) {
            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 imports.
            // Let's remove the old one and go with the new one.
            this.configurationClasses.remove(configClass);
            this.knownSuperclasses.values().removeIf(configClass::equals);
        }
    }

    // Recursively process the configuration class and its superclass hierarchy.
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        //這個裡面會註冊BeanDefinition,重點看這步
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);
    //一個map,用來存放掃描出來的bean(注意這裡的bean不是物件,僅僅bean的資訊,因為還沒到例項化這一步)
    this.configurationClasses.put(configClass, configClass);
}
複製程式碼
doProcessConfigurationClass 方法
//真正解析配置類的方法
//注意這個ConfigurationClass物件是從ConfigurationClassPostProcessor中傳過來的
//@Bean、@Import(三種)解析出來的類都放入ConfigurationClass物件中
//ConfigurationClassPostProcessor會呼叫this.reader.loadBeanDefinitions(configClasses)方法來統一解析
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
    //處理所有@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
            //掃描普通類=componentScan=com.test
            //這裡掃描出來所有@@Component
            //並且把掃描的出來的普通bean放到map當中
            //在這注冊普通的BeanDefinition,跟進去
            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
            //檢查掃描出來的類當中是否還有configuration
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                //檢查  todo
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    //如果掃描@ComponentScan裡面還有配置類,進行遞迴,回到上面的parse方法
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }

    /**
		 * 上面的程式碼就是掃描普通類----@Component
		 * 並且放到了map當中
		 */
    // Process any @Import annotations
    //處理@Import  imports 3種情況
    //ImportSelector
    //普通類
    //ImportBeanDefinitionRegistrar
    //這裡和內部地櫃呼叫時候的情況不同
    /**
		 * 這裡處理的import是需要判斷我們的類當中時候有@Import註解
		 * 如果有這把@Import當中的值拿出來,是一個類
		 * 比如@Import(xxxxx.class),那麼這裡便把xxxxx傳進去進行解析
		 * 在解析的過程中如果發覺是一個importSelector那麼就回撥selector的方法
		 * 返回一個字串(類名),通過這個字串得到一個類
		 * 繼而在遞迴呼叫本方法來處理這個類
		 *
		 * 判斷一組類是不是imports(3種import)
		 *
		 *
		 */
    //跟進去
    processImports(configClass, sourceClass, getImports(sourceClass), true);

    // Process any @ImportResource annotations
    AnnotationAttributes importResource =
        AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    if (importResource != null) {
        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 = retrieveBeanMethodMetadata(sourceClass);
    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 != null && !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;
}

複製程式碼
parse 方法
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    //這裡的scanner是重新建立的,不是初始化AnnotationConfigApplicationContext時建立的物件
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                                                                                componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    //BeanNameGenerator
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
                                 BeanUtils.instantiateClass(generatorClass));

    //web應用的,跳過
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
        scanner.setScopedProxyMode(scopedProxyMode);
    }
    else {
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }

    scanner.setResourcePattern(componentScan.getString("resourcePattern"));

    //遍歷當中的過濾
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addIncludeFilter(typeFilter);
        }
    }
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addExcludeFilter(typeFilter);
        }
    }

    //預設false
    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
        scanner.getBeanDefinitionDefaults().setLazyInit(true);
    }

    //獲取@ComponentScan註解的值
    Set<String> basePackages = new LinkedHashSet<>();
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
        String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                                                               ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        Collections.addAll(basePackages, tokenized);
    }
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
        basePackages.add(ClassUtils.getPackageName(clazz));
    }
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return declaringClass.equals(className);
        }
    });
	//這個是核心,掃描路徑並把符合條件的類轉換為BeanDefinition物件
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

複製程式碼
doScan 方法
//掃描路徑
//把符合條件的類轉換為對應的BeanDefinition物件
//為BeanDefinition物件賦值
//把BeanDefinition物件註冊到容器中
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        //掃描basePackage路徑下的java檔案
        //符合條件的並把它轉成BeanDefinition型別,跟進去
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

        for (BeanDefinition candidate : candidates) {
            //解析scope屬性
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                //如果這個類是AbstractBeanDefinition的子類
                //則為他設定預設值,比如lazy,init destory
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                //檢查並且處理常用的註解
                //這裡的處理主要是指把常用註解的值設定到AnnotatedBeanDefinition當中
                //當前前提是這個類必須是AnnotatedBeanDefinition型別的,說白了就是加了註解的類
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                //加入到map當中,這裡是註冊功能把BeanDefinition註冊到容器中
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

複製程式碼
findCandidateComponents 方法
//掃描包,空殼方法
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    else {
        //看這個
        return scanCandidateComponents(basePackage);
    }
}

複製程式碼
scanCandidateComponents 方法
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        //這一步會把packageSearchPath的值修改為 classpath*:com/ktcatv/**/*.class
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        //asm 讀取class檔案生成Resource物件,跳過吧,內容太多了不是重點
        Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();
        for (Resource resource : resources) {
            if (traceEnabled) {
                logger.trace("Scanning " + resource);
            }
            if (resource.isReadable()) {
                try {
                    //這裡可以把Resource物件轉換為ScannedGenericBeanDefinition物件,只記住這點就行了
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    if (isCandidateComponent(metadataReader)) {
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        }
                        else {
                            if (debugEnabled) {
                                logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        }
                    }
                    else {
                        if (traceEnabled) {
                            logger.trace("Ignored because not matching any filter: " + resource);
                        }
                    }
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                        "Failed to read candidate component class: " + resource, ex);
                }
            }
            else {
                if (traceEnabled) {
                    logger.trace("Ignored because not readable: " + resource);
                }
            }
        }
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    //返回解析後的BeanDefinition集合
    return candidates;
}

複製程式碼
  • 回到doScan方法接著看
registerBeanDefinition 方法
//註冊BeanDefinition,空殼方法
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    //跟進去
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

//這個才是真實的註冊BeanDefinition物件的方法
public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    //這裡註冊BeanDefinition,這個跟進去
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // 註冊別名,如果有的話
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

//DefaultListabaleBeanFactory中的方法
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Validation of bean definition failed", ex);
        }
    }

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                                                   "': There is already [" + existingDefinition + "] bound.");
        }
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (logger.isWarnEnabled()) {
                logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
            }
        }
        else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isInfoEnabled()) {
                logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
            }
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                             "' with an equivalent definition: replacing [" + existingDefinition +
                             "] with [" + beanDefinition + "]");
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        if (hasBeanCreationStarted()) {
            //這裡是處理已經被註冊的邏輯,應該是被其他的BeanFactoryPostProcessor修改後進入這裡
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
            // 這裡是正常的邏輯,註冊BeanDefinition就是放進beanDefinitionMap物件中
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

複製程式碼
  • 回到 doProcessConfigurationClass 方法繼續看
processImports 方法
//處理@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)) {
                    // 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
                        //如果是一個普通類,會進else
                        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
                    Class<?> candidateClass = candidate.loadClass();
                    ImportBeanDefinitionRegistrar registrar =
                        BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                    ParserStrategyUtils.invokeAwareMethods(
                        registrar, this.environment, this.resourceLoader, this.registry);
                    //新增到一個list當中和importselector不同
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                else {
                    // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                    // process it as an @Configuration class
                    // 否則,加入到importStack後呼叫processConfigurationClass 進行處理
                    //processConfigurationClass裡面主要就是把類放到configurationClasses
                    //configurationClasses是一個集合,會在後面拿出來解析成bd繼而註冊
                    //可以看到普通類在掃描出來的時候就被註冊了
                    //如果是importSelector,會先放到configurationClasses後面進行出來註冊
                    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 imports candidates for configuration class [" +
                configClass.getMetadata().getClassName() + "]", ex);
        }
        finally {
            this.importStack.pop();
        }
    }
}

複製程式碼
  • 回到 processConfigBeanDefinitions 方法繼續
loadBeanDefinitions 方法
//空殼方法
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
            //跟進去
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

複製程式碼
loadBeanDefinitionsForConfigurationClass 方法
private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, 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;
		}

		//如果一個類是被import的,會被spring標記
		//在這裡完成註冊
		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		//@Bean
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		 //xml
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

		//註冊Registrar
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

複製程式碼
  • 到這就把配置檔案解析完成了

ConfigurationClassPostProcessor 小結

  • ConfigurationClassPostProcessor 是Spring內部最重要的一個BeanDefinitionRegistryPostProcesso的實現類,它的主要工作就是解析配置檔案
  • ConfigurationClassPostProcessor 工作流程
      1. 從容器中獲取所有的BeanDefinition物件
      2. 篩選出需要解析的配置類的BeanDefinition物件
      3. 遍歷篩選出來的BeanDefinition物件,進行解析
      4. 解析@ComponentScan獲取路徑
      5. 掃描路徑下符合條件的類,把符合條件的類轉換為對應的BeanDefinition,這裡不會處理@Bean和@Import只會新增到ConfigurationClass物件中
      6. 註冊轉換的BeanDefinition物件
      7. 使用 ConfigurationClassBeanDefinitionReader 載入上面掃描出來的其他類(@Bean和@Import)轉換為BeanDefinition並註冊到容器中

BeanFactoryPostProcessor 的自定義使用

Dao類

public interface IDao {
	void query();
}

@Repository("indexDao")
public class IndexDao implements IDao {
	@Override
	public void query() {
		System.out.println("index dao");
	}
}

複製程式碼

Service類

public interface IService {
	void service();
}

//注意這裡沒有註解,不能被Spring掃描到
public class IndexService implements IService {
	@Override
	public void service() {
		System.out.println("service");
	}
}

複製程式碼

Appconfig類

@Configuration
@ComponentScan("com.ktcatv")
public class Appconfig {
}

複製程式碼

BeanFactoryPostPorcessor類

@Component
public class BeanFactoryPostPorcessorTest implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        //這裡獲取了IndexDao的BeanDefinition物件,修改了它的beanCalss屬性
		BeanDefinition indexDao = beanFactory.getBeanDefinition("indexDao");
		indexDao.setBeanClassName(IndexService.class.getName());
	}
}

複製程式碼

Test類

public class Test {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);
        //可以正常執行,說明上面的BeanFactoryPostPorcessorTest類成功修改了 IndexDao 類的例項化過程
		IService service = configApplicationContext.getBean(IService.class);
		service.service();
	}
}

複製程式碼

相關文章