zoukankan      html  css  js  c++  java
  • Spring Boot 配置类3-流程核心方法doProcessConfigurationClass

    doProcessConfigurationClass方法

    	@Nullable
    	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
    			throws IOException {
    
    		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
    			// 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.info("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 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());
    					}
    				}
    			}
    		}
    
    		// Process any @Import annotations
    		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;
    	}
    

      

    1、processMemberClasses(configClass, sourceClass);方法

    	private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    		Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
    		if (!memberClasses.isEmpty()) {
    			List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
    			for (SourceClass memberClass : memberClasses) {
    				if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
    						!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
    					candidates.add(memberClass);
    				}
    			}
    			OrderComparator.sort(candidates);
    			for (SourceClass candidate : candidates) {
    				if (this.importStack.contains(configClass)) {
    					this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    				}
    				else {
    					this.importStack.push(configClass);
    					try {
    						processConfigurationClass(candidate.asConfigClass(configClass));
    					}
    					finally {
    						this.importStack.pop();
    					}
    				}
    			}
    		}
    	}
    

      首先判断是否有内部类,没有就返回。

    1)我们模拟创建两个内部类,分别为Test1和Test2

    2)然后进入processMemberClasses方法调式

    2、接着处理PropertySource 注解配置

     1)进入processPropertySource方法

    factory.createPropertySource 方法中会加载demo.properties这个文件

     2)进入addPropertySource方法

    3、接着处理ComponentScan注解 

    1)SpringBoot注解已经包括了ComponetScan注解了

     

     2) 进入ComponetScan处理代码

    3) 然后进入this.componetScanParser.parse方法

    	public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
    				componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
    
    		Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    		boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    		scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
    				BeanUtils.instantiateClass(generatorClass));
    
    		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);
    			}
    		}
    
    		boolean lazyInit = componentScan.getBoolean("lazyInit");
    		if (lazyInit) {
    			scanner.getBeanDefinitionDefaults().setLazyInit(true);
    		}
    
    		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);
    			}
    		});
    		return scanner.doScan(StringUtils.toStringArray(basePackages));
    	}
    
    

      实例化ClassPathBeanDefinitionScanner 类,然后设置一些属性。

    4)调用scanner.doScan方法

    	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) {
    			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    			for (BeanDefinition candidate : candidates) {
    				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    				candidate.setScope(scopeMetadata.getScopeName());
    				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    				if (candidate instanceof AbstractBeanDefinition) {
    					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    				}
    				if (candidate instanceof 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);
    					registerBeanDefinition(definitionHolder, this.registry);
    				}
    			}
    		}
    		return beanDefinitions;
    	}
    

      

    a) findCandidateComponents

    	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
    			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    		}
    		else {
    			return scanCandidateComponents(basePackage);
    		}
    	}
    

      

    b)进入scanCandidateComponents方法

    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    		Set<BeanDefinition> candidates = new LinkedHashSet<>();
    		try {
    			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
    					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
    			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 {
    						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);
    		}
    		return candidates;
    	}
    

      获得包下面所有的class文件

    getResourcePatternResolver().getResources(packageSearchPath)
    

      如下图所示

     然后遍历这些资源,isCandidateComponent用来决定这个类是否要添加进来。

    	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    		for (TypeFilter tf : this.excludeFilters) {
    			if (tf.match(metadataReader, getMetadataReaderFactory())) {
    				return false;
    			}
    		}
    		for (TypeFilter tf : this.includeFilters) {
    			if (tf.match(metadataReader, getMetadataReaderFactory())) {
    				return isConditionMatch(metadataReader);
    			}
    		}
    		return false;
    	}
    

      

    5)遍历BeanDefinition集合candidates


    4、接着处理Import注解。可以通过Import导入相应的类

     进入processImport方法

    	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) {
    					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 (selector instanceof DeferredImportSelector) {
    							this.deferredImportSelectorHandler.handle(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();
    			}
    		}
    	}
    

      


    5、接着处理ImportResource注解。

     增加ImportResource注解。

    @SpringBootApplication
    @MapperScan("com.example.demo.mapper")
    @PropertySource({"demo.properties"})
    @ImportResource("ioc/demo.xml")
    public class Sb2Application {
    }
    

     进入处理ImportResource注解代码

    进入addImportedResource方法

     


    6、接着处理Bean方法。

    增加Bean方法

    然后将bean方法添加到configClass中


    7、接着处理默认方法

    1)接口默认方法处理,是JDK8中引入的。

     2) 接着增加接口,里面有一个默认方法

     3)Sb2Application实现了SuperConfiguration这个接口

      

    4)在processInterfaces里将BeanMethod方法添加到configClass中


    8、接着处理父类。

    最后返回sourceClass的父类

  • 相关阅读:
    chrome新版本flash无法在http网站上运行的解决办法
    SSO单点登录三种情况的实现方式详解(转载)
    解决请求筛选模块被配置为拒绝包含的查询字符串过长的请求(原创)
    更改mysql默认字符集 (转载)
    用TextWriterTraceListener实现log文件记录 (转载)
    PO BO VO DTO POJO DAO概念及其作用
    SqlServer 的一个坑
    关于windows服务注册的问题
    原生js的数组除重复
    ES6 箭头函数下的this指向和普通函数的this对比
  • 原文地址:https://www.cnblogs.com/linlf03/p/12436148.html
Copyright © 2011-2022 走看看