zoukankan      html  css  js  c++  java
  • SpringBoot启动过程中,候选类的过滤和加载

    几个初始化要点:
    在调用SpringApplication的构造函数时,调用了setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))方法时,底层调用了loadSpringFactories方法,加载了spring.factories下的类 ,并进行了缓存 ,如下,然后将加载到的初始化类型的类放入了list容器中,供后面调用

    	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    		Map<String, List<String>> result = cache.get(classLoader);
    		if (result != null) {
    			return result;
    		}
    
    		result = new HashMap<>();
    		try {
    			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
    			while (urls.hasMoreElements()) {
    				URL url = urls.nextElement();
    				UrlResource resource = new UrlResource(url);
    				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    				for (Map.Entry<?, ?> entry : properties.entrySet()) {
    					String factoryTypeName = ((String) entry.getKey()).trim();
    					String[] factoryImplementationNames =
    							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
    					for (String factoryImplementationName : factoryImplementationNames) {
    						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
    								.add(factoryImplementationName.trim());
    					}
    				}
    			}
    
    			// Replace all lists with unmodifiable lists containing unique elements
    			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
    					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
    			cache.put(classLoader, result);
    		}
    		catch (IOException ex) {
    			throw new IllegalArgumentException("Unable to load factories from location [" +
    					FACTORIES_RESOURCE_LOCATION + "]", ex);
    		}
    		return result;
    	}
    

    SpringBoot在启动的过程中,加载到主类后,根据主类上配置的注解信息,由ConfigurationClassParser对启动类进行解析,在parse的过程中,对includeFilters,excludeFilters进行了解析,添加到了类型过滤器中,而且在解析过程中,以内部类的形式,添加了一个排除过滤器,方便排除自身,在后面有用到,

    接着处理包括@ComponentScan、@ComponentScans,当解析到basePackages时,对包路径下的类使用ClassPathBeanDefinitonScanner对类进行处理;将对应的类资源包装成Resource,然后对类进行类型过滤,获取到符合条件的候选型加载类。

    public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
    
      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);
    				}
    				try {
    					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                                            //此处根据元信息对类进行过滤
    					if (isCandidateComponent(metadataReader)) {
    						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
    						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 (FileNotFoundException ex) {
    					if (traceEnabled) {
    						logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
    					}
    				}
    				catch (Throwable ex) {
    					throw new BeanDefinitionStoreException(
    							"Failed to read candidate component class: " + resource, ex);
    				}
    			}
    		}
    		catch (IOException ex) {
    			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    		}
    		return candidates;
    	}
    
            //此处根据元数据信息对类进行过滤
    	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;
    	}
    }
    


    tf.match(metadataReader, getMetadataReaderFactory()),方法首先对自身做了判断,如果等于自身,则排除掉。默认的排除过滤器,包括自身创建的内部类,AutoConfigurationExcludeFilter、TypeExcludeFilter三个排除过滤器
    默认的包含过滤器包括两个注解类型分别为@Component和@ManagedBean的AnnotationTypeFilter

    	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
    			throws IOException {
    
    		// This method optimizes avoiding unnecessary creation of ClassReaders
    		// as well as visiting over those readers.
    
    		if (matchSelf(metadataReader)) {
    			return true;
    		}
    		ClassMetadata metadata = metadataReader.getClassMetadata();
    		if (matchClassName(metadata.getClassName())) {
    			return true;
    		}
    
    		if (this.considerInherited) {
    			String superClassName = metadata.getSuperClassName();
    			if (superClassName != null) {
    				// Optimization to avoid creating ClassReader for super class.
    				Boolean superClassMatch = matchSuperClass(superClassName);
    				if (superClassMatch != null) {
    					if (superClassMatch.booleanValue()) {
    						return true;
    					}
    				}
    				else {
    					// Need to read super class to determine a match...
    					try {
    						if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
    							return true;
    						}
    					}
    					catch (IOException ex) {
    						if (logger.isDebugEnabled()) {
    							logger.debug("Could not read super class [" + metadata.getSuperClassName() +
    									"] of type-filtered class [" + metadata.getClassName() + "]");
    						}
    					}
    				}
    			}
    		}
    
    		if (this.considerInterfaces) {
    			for (String ifc : metadata.getInterfaceNames()) {
    				// Optimization to avoid creating ClassReader for super class
    				Boolean interfaceMatch = matchInterface(ifc);
    				if (interfaceMatch != null) {
    					if (interfaceMatch.booleanValue()) {
    						return true;
    					}
    				}
    				else {
    					// Need to read interface to determine a match...
    					try {
    						if (match(ifc, metadataReaderFactory)) {
    							return true;
    						}
    					}
    					catch (IOException ex) {
    						if (logger.isDebugEnabled()) {
    							logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
    									metadata.getClassName() + "]");
    						}
    					}
    				}
    			}
    		}
    
    		return false;
    	}
    

    matchSelf(metadataReader)方法想要生效,需要添加自定义方法
    matchClassName(metadata.getClassName())方法调用的是自身添加的内部类,在加载候选类的时候,将自己排除在外,因为自己本身已经处于beanDefinitionMap中。
    对于符合候选项的类包装成ScannedGenericBeanDefinition即一般的扫描BeanDefinition,
    扫描到候选项之后,将BeanDefinition放入到map中。
    在首次对@ComponentScan、@ComponentScans进行注解类的解析并加载到候选类之后,然后检查扫描的定义集是否有任何进一步的配置类,并在需要时进行递归解析,如果满足配置类,其中难点在于此处,由于内部循环调用doProcessConfigurationClass()会导致开发者晕头转向。

    则继续调用ClassPathBeanDefinitonScanner进行parse处理

    		
              	                // 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());
    					}
    				}
    

    判断是否是配置类

    	public static boolean checkConfigurationClassCandidate(
    			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
    
    		String className = beanDef.getBeanClassName();
    		if (className == null || beanDef.getFactoryMethodName() != null) {
    			return false;
    		}
    
    		AnnotationMetadata metadata;
    		if (beanDef instanceof AnnotatedBeanDefinition &&
    				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
    			// Can reuse the pre-parsed metadata from the given BeanDefinition...
    			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.
    			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
    			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
    					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
    					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
    					EventListenerFactory.class.isAssignableFrom(beanClass)) {
    				return false;
    			}
    			metadata = AnnotationMetadata.introspect(beanClass);
    		}
    		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;
    			}
    		}
    
    		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
    		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
    			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
    		}
    		else if (config != null || isConfigurationCandidate(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;
    	}
    
    

    方法内部调用了isConfigurationCandidate方法用来判断元数据信息是否满足ConfigurationCandidate,并且满足是Configuration类的话,会调用hasBeanMethods方法用来判断是否包含@Bean注解

    abstract class ConfigurationClassUtils {
    
    	static {
    		candidateIndicators.add(Component.class.getName());
    		candidateIndicators.add(ComponentScan.class.getName());
    		candidateIndicators.add(Import.class.getName());
    		candidateIndicators.add(ImportResource.class.getName());
    	}
    
    	public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
    		// Do not consider an interface or an annotation...
    		if (metadata.isInterface()) {
    			return false;
    		}
    
    		// Any of the typical annotations found?
    		for (String indicator : candidateIndicators) {
    			if (metadata.isAnnotated(indicator)) {
    				return true;
    			}
    		}
    
    		// Finally, let's look for @Bean methods...
    		return hasBeanMethods(metadata);
    	}
    }
    

    在解析完@ComponentScan注解之后,我们来到下一个重量级导入类功能注解@Import

    	private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
    			throws IOException {
    
    		if (visited.add(sourceClass)) {
    			for (SourceClass annotation : sourceClass.getAnnotations()) {
    				String annName = annotation.getMetadata().getClassName();
    				if (!annName.equals(Import.class.getName())) {
    					collectImports(annotation, imports, visited);
    				}
    			}
    			imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
    		}
    	}
    
    		public Collection<SourceClass> getAnnotationAttributes(String annType, String attribute) throws IOException {
    			Map<String, Object> annotationAttributes = this.metadata.getAnnotationAttributes(annType, true);
    			if (annotationAttributes == null || !annotationAttributes.containsKey(attribute)) {
    				return Collections.emptySet();
    			}
    			String[] classNames = (String[]) annotationAttributes.get(attribute);
    			Set<SourceClass> result = new LinkedHashSet<>();
    			for (String className : classNames) {
    				result.add(getRelated(className));
    			}
    			return result;
    		}
    

    通过循环获取,获取到了多个内部类配置的@Import
    此处加载到的源类是根据注解递归获取的。根据启动类@SpringBootApplication加载到的源类有

    0 = {ConfigurationClassParser$SourceClass@3980} "com.bail.user.service.UserProviderBootstrap"
    1 = {ConfigurationClassParser$SourceClass@4046} "org.springframework.boot.autoconfigure.SpringBootApplication"
    2 = {ConfigurationClassParser$SourceClass@4017} "org.springframework.boot.SpringBootConfiguration"
    3 = {ConfigurationClassParser$SourceClass@4035} "org.springframework.context.annotation.Configuration"
    4 = {ConfigurationClassParser$SourceClass@3953} "java.lang.Object"
    5 = {ConfigurationClassParser$SourceClass@4189} "org.springframework.boot.autoconfigure.EnableAutoConfiguration"
    6 = {ConfigurationClassParser$SourceClass@4222} "org.springframework.boot.autoconfigure.AutoConfigurationPackage"
    7 = {ConfigurationClassParser$SourceClass@4364} "org.springframework.context.annotation.ComponentScan"
    8 = {ConfigurationClassParser$SourceClass@4497} "org.springframework.context.annotation.ImportResource"
    

    首先是:根据源class:AutoConfigurationPackages获取到 AutoConfigurationPackages$Registrar
    根据源class:AutoConfigurationPackages获取到 AutoConfigurationPackages$Registrar
    根据EnableAutoConfiguration加载到AutoConfigurationImportSelector注解;
    @SpringBootApplication由3个注解组成

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    
    }
    
    
    @Configuration
    @Indexed
    public @interface SpringBootConfiguration {
    }
    
    @Component
    public @interface Configuration {
    }
    
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)//自动配置选择导入类
    public @interface EnableAutoConfiguration {
    
    }
    
    //自动配置包注册类
    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
    }
    
    @Repeatable(ComponentScans.class)
    public @interface ComponentScan {
    }
    

    进过getImports()方法后,加载到的类有如下两个类:

    0 = {ConfigurationClassParser$SourceClass@4618} "org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar"
    1 = {ConfigurationClassParser$SourceClass@4619} "org.springframework.boot.autoconfigure.AutoConfigurationImportSelector"
    

    然后对加载到的类进行解析processImports
    AutoConfigurationPackages$Registrar符合ImportBeanDefinitionRegistrar.class,创建AutoConfigurationPackages$Registrar实例对象,随后在map容器中放入了value=启动类的ImportBeanDefinitionRegistrar;
    AutoConfigurationImportSelector符合ImportSelector类,创建AutoConfigurationImportSelector实例selector之后,调用deferredImportSelectorHandler处理selector,将selector添加到了list容器中;
    这个过程仅仅将实例对象放到了对应的容器中。

    随后开始解析@ImportResource 注解。解析到的资源如下:

    "locations" -> {String[1]@5157} ["dubbo-provider.xml"]
    "reader" -> {Class@3159} "interface org.springframework.beans.factory.support.BeanDefinitionReader"
    "value" -> {String[1]@5159} ["dubbo-provider.xml"]
    
    将解析到的资源文件存储到了configClass的map容器中。
    
    接下来继续解析@Bean注解
    
    在解析完毕后,将解析到保存解析内容的configClass添加到configurationClasses map类型容器中。
    
    随后调用this.deferredImportSelectorHandler.process()对importSelector进行解析。
    其中,ConfigurationClassParser有多个导入类的内部类
    

    class ConfigurationClassParser {

    private static class ImportStack extends ArrayDeque<ConfigurationClass> implements ImportRegistry {
    

    }

    private class DeferredImportSelectorHandler {
    

    }
    private class DeferredImportSelectorGroupingHandler {
    }
    private static class DeferredImportSelectorHolder {
    }
    private static class DeferredImportSelectorGrouping {
    }
    private static class DefaultDeferredImportSelectorGroup implements Group {
    }
    }

    内部调用了DeferredImportSelectorGroupingHandler的register对deferredImports进行处理,
    在解析AutoConfigurationImportSlector的过程中,调用了一个getImports()方法,而这个方法底层调用的是SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()方法:
    
    ```java
    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
    		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
    				getBeanClassLoader());
    		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
    				+ "are using a custom packaging, make sure that file is correct.");
    		return configurations;
    	}
    }
    
    	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
                    //此处的cache中,已经缓存了spring.factories文件下要加载的不同类型的类
    		Map<String, List<String>> result = cache.get(classLoader);
    		if (result != null) {
    			return result;
    		}
    
    		result = new HashMap<>();
    		try {
    			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
    			while (urls.hasMoreElements()) {
    				URL url = urls.nextElement();
    				UrlResource resource = new UrlResource(url);
    				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    				for (Map.Entry<?, ?> entry : properties.entrySet()) {
    					String factoryTypeName = ((String) entry.getKey()).trim();
    					String[] factoryImplementationNames =
    							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
    					for (String factoryImplementationName : factoryImplementationNames) {
    						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
    								.add(factoryImplementationName.trim());
    					}
    				}
    			}
    
    			// Replace all lists with unmodifiable lists containing unique elements
    			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
    					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
    			cache.put(classLoader, result);
    		}
    		catch (IOException ex) {
    			throw new IllegalArgumentException("Unable to load factories from location [" +
    					FACTORIES_RESOURCE_LOCATION + "]", ex);
    		}
    		return result;
    	}
    

    此处我们只需要返回类型为org.springframework.boot.autoconfigure.EnableAutoConfiguration的类------------恢复内容开始------------
    几个初始化要点:
    在调用SpringApplication的构造函数时,调用了setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))方法时,底层调用了loadSpringFactories方法,加载了spring.factories下的类 ,并进行了缓存 ,如下,然后将加载到的初始化类型的类放入了list容器中,供后面调用

    	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    		Map<String, List<String>> result = cache.get(classLoader);
    		if (result != null) {
    			return result;
    		}
    
    		result = new HashMap<>();
    		try {
    			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
    			while (urls.hasMoreElements()) {
    				URL url = urls.nextElement();
    				UrlResource resource = new UrlResource(url);
    				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    				for (Map.Entry<?, ?> entry : properties.entrySet()) {
    					String factoryTypeName = ((String) entry.getKey()).trim();
    					String[] factoryImplementationNames =
    							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
    					for (String factoryImplementationName : factoryImplementationNames) {
    						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
    								.add(factoryImplementationName.trim());
    					}
    				}
    			}
    
    			// Replace all lists with unmodifiable lists containing unique elements
    			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
    					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
    			cache.put(classLoader, result);
    		}
    		catch (IOException ex) {
    			throw new IllegalArgumentException("Unable to load factories from location [" +
    					FACTORIES_RESOURCE_LOCATION + "]", ex);
    		}
    		return result;
    	}
    

    SpringBoot在启动的过程中,加载到主类后,根据主类上配置的注解信息,由ConfigurationClassParser对启动类进行解析,在parse的过程中,对includeFilters,excludeFilters进行了解析,添加到了类型过滤器中,而且在解析过程中,以内部类的形式,添加了一个排除过滤器,方便排除自身,在后面有用到,

    接着处理包括@ComponentScan、@ComponentScans,当解析到basePackages时,对包路径下的类使用ClassPathBeanDefinitonScanner对类进行处理;将对应的类资源包装成Resource,然后对类进行类型过滤,获取到符合条件的候选型加载类。

    public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
    
      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);
    				}
    				try {
    					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                                            //此处根据元信息对类进行过滤
    					if (isCandidateComponent(metadataReader)) {
    						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
    						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 (FileNotFoundException ex) {
    					if (traceEnabled) {
    						logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
    					}
    				}
    				catch (Throwable ex) {
    					throw new BeanDefinitionStoreException(
    							"Failed to read candidate component class: " + resource, ex);
    				}
    			}
    		}
    		catch (IOException ex) {
    			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    		}
    		return candidates;
    	}
    
            //此处根据元数据信息对类进行过滤
    	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;
    	}
    }
    


    tf.match(metadataReader, getMetadataReaderFactory()),方法首先对自身做了判断,如果等于自身,则排除掉。默认的排除过滤器,包括自身创建的内部类,AutoConfigurationExcludeFilter、TypeExcludeFilter三个排除过滤器
    默认的包含过滤器包括两个注解类型分别为@Component和@ManagedBean的AnnotationTypeFilter

    	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
    			throws IOException {
    
    		// This method optimizes avoiding unnecessary creation of ClassReaders
    		// as well as visiting over those readers.
    
    		if (matchSelf(metadataReader)) {
    			return true;
    		}
    		ClassMetadata metadata = metadataReader.getClassMetadata();
    		if (matchClassName(metadata.getClassName())) {
    			return true;
    		}
    
    		if (this.considerInherited) {
    			String superClassName = metadata.getSuperClassName();
    			if (superClassName != null) {
    				// Optimization to avoid creating ClassReader for super class.
    				Boolean superClassMatch = matchSuperClass(superClassName);
    				if (superClassMatch != null) {
    					if (superClassMatch.booleanValue()) {
    						return true;
    					}
    				}
    				else {
    					// Need to read super class to determine a match...
    					try {
    						if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
    							return true;
    						}
    					}
    					catch (IOException ex) {
    						if (logger.isDebugEnabled()) {
    							logger.debug("Could not read super class [" + metadata.getSuperClassName() +
    									"] of type-filtered class [" + metadata.getClassName() + "]");
    						}
    					}
    				}
    			}
    		}
    
    		if (this.considerInterfaces) {
    			for (String ifc : metadata.getInterfaceNames()) {
    				// Optimization to avoid creating ClassReader for super class
    				Boolean interfaceMatch = matchInterface(ifc);
    				if (interfaceMatch != null) {
    					if (interfaceMatch.booleanValue()) {
    						return true;
    					}
    				}
    				else {
    					// Need to read interface to determine a match...
    					try {
    						if (match(ifc, metadataReaderFactory)) {
    							return true;
    						}
    					}
    					catch (IOException ex) {
    						if (logger.isDebugEnabled()) {
    							logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
    									metadata.getClassName() + "]");
    						}
    					}
    				}
    			}
    		}
    
    		return false;
    	}
    

    matchSelf(metadataReader)方法想要生效,需要添加自定义方法
    matchClassName(metadata.getClassName())方法调用的是自身添加的内部类,在加载候选类的时候,将自己排除在外,因为自己本身已经处于beanDefinitionMap中。
    对于符合候选项的类包装成ScannedGenericBeanDefinition即一般的扫描BeanDefinition,
    扫描到候选项之后,将BeanDefinition放入到map中。
    在首次对@ComponentScan、@ComponentScans进行注解类的解析并加载到候选类之后,然后检查扫描的定义集是否有任何进一步的配置类,并在需要时进行递归解析,如果满足配置类,其中难点在于此处,由于内部循环调用doProcessConfigurationClass()会导致开发者晕头转向。

    则继续调用ClassPathBeanDefinitonScanner进行parse处理

    		
              	                // 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());
    					}
    				}
    

    判断是否是配置类

    	public static boolean checkConfigurationClassCandidate(
    			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
    
    		String className = beanDef.getBeanClassName();
    		if (className == null || beanDef.getFactoryMethodName() != null) {
    			return false;
    		}
    
    		AnnotationMetadata metadata;
    		if (beanDef instanceof AnnotatedBeanDefinition &&
    				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
    			// Can reuse the pre-parsed metadata from the given BeanDefinition...
    			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.
    			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
    			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
    					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
    					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
    					EventListenerFactory.class.isAssignableFrom(beanClass)) {
    				return false;
    			}
    			metadata = AnnotationMetadata.introspect(beanClass);
    		}
    		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;
    			}
    		}
    
    		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
    		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
    			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
    		}
    		else if (config != null || isConfigurationCandidate(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;
    	}
    
    

    方法内部调用了isConfigurationCandidate方法用来判断元数据信息是否满足ConfigurationCandidate,并且满足是Configuration类的话,会调用hasBeanMethods方法用来判断是否包含@Bean注解

    abstract class ConfigurationClassUtils {
    
    	static {
    		candidateIndicators.add(Component.class.getName());
    		candidateIndicators.add(ComponentScan.class.getName());
    		candidateIndicators.add(Import.class.getName());
    		candidateIndicators.add(ImportResource.class.getName());
    	}
    
    	public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
    		// Do not consider an interface or an annotation...
    		if (metadata.isInterface()) {
    			return false;
    		}
    
    		// Any of the typical annotations found?
    		for (String indicator : candidateIndicators) {
    			if (metadata.isAnnotated(indicator)) {
    				return true;
    			}
    		}
    
    		// Finally, let's look for @Bean methods...
    		return hasBeanMethods(metadata);
    	}
    }
    

    在解析完@ComponentScan注解之后,我们来到下一个重量级导入类功能注解@Import

    	private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
    			throws IOException {
    
    		if (visited.add(sourceClass)) {
    			for (SourceClass annotation : sourceClass.getAnnotations()) {
    				String annName = annotation.getMetadata().getClassName();
    				if (!annName.equals(Import.class.getName())) {
    					collectImports(annotation, imports, visited);
    				}
    			}
    			imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
    		}
    	}
    
    		public Collection<SourceClass> getAnnotationAttributes(String annType, String attribute) throws IOException {
    			Map<String, Object> annotationAttributes = this.metadata.getAnnotationAttributes(annType, true);
    			if (annotationAttributes == null || !annotationAttributes.containsKey(attribute)) {
    				return Collections.emptySet();
    			}
    			String[] classNames = (String[]) annotationAttributes.get(attribute);
    			Set<SourceClass> result = new LinkedHashSet<>();
    			for (String className : classNames) {
    				result.add(getRelated(className));
    			}
    			return result;
    		}
    

    通过循环获取,获取到了多个内部类配置的@Import
    此处加载到的源类是根据注解递归获取的。根据启动类@SpringBootApplication加载到的源类有

    0 = {ConfigurationClassParser$SourceClass@3980} "com.bail.user.service.UserProviderBootstrap"
    1 = {ConfigurationClassParser$SourceClass@4046} "org.springframework.boot.autoconfigure.SpringBootApplication"
    2 = {ConfigurationClassParser$SourceClass@4017} "org.springframework.boot.SpringBootConfiguration"
    3 = {ConfigurationClassParser$SourceClass@4035} "org.springframework.context.annotation.Configuration"
    4 = {ConfigurationClassParser$SourceClass@3953} "java.lang.Object"
    5 = {ConfigurationClassParser$SourceClass@4189} "org.springframework.boot.autoconfigure.EnableAutoConfiguration"
    6 = {ConfigurationClassParser$SourceClass@4222} "org.springframework.boot.autoconfigure.AutoConfigurationPackage"
    7 = {ConfigurationClassParser$SourceClass@4364} "org.springframework.context.annotation.ComponentScan"
    8 = {ConfigurationClassParser$SourceClass@4497} "org.springframework.context.annotation.ImportResource"
    

    首先是:根据源class:AutoConfigurationPackages获取到 AutoConfigurationPackages$Registrar
    根据源class:AutoConfigurationPackages获取到 AutoConfigurationPackages$Registrar
    根据EnableAutoConfiguration加载到AutoConfigurationImportSelector注解;
    @SpringBootApplication由3个注解组成

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    
    }
    
    
    @Configuration
    @Indexed
    public @interface SpringBootConfiguration {
    }
    
    @Component
    public @interface Configuration {
    }
    
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)//自动配置选择导入类
    public @interface EnableAutoConfiguration {
    
    }
    
    //自动配置包注册类
    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
    }
    
    @Repeatable(ComponentScans.class)
    public @interface ComponentScan {
    }
    

    进过getImports()方法后,加载到的类有如下两个类:

    0 = {ConfigurationClassParser$SourceClass@4618} "org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar"
    1 = {ConfigurationClassParser$SourceClass@4619} "org.springframework.boot.autoconfigure.AutoConfigurationImportSelector"
    

    然后对加载到的类进行解析processImports
    AutoConfigurationPackages$Registrar符合ImportBeanDefinitionRegistrar.class,创建AutoConfigurationPackages$Registrar实例对象,随后在map容器中放入了value=启动类的ImportBeanDefinitionRegistrar;
    AutoConfigurationImportSelector符合ImportSelector类,创建AutoConfigurationImportSelector实例selector之后,调用deferredImportSelectorHandler处理selector,将selector添加到了list容器中;
    这个过程仅仅将实例对象放到了对应的容器中。

    随后开始解析@ImportResource 注解。解析到的资源如下:

    "locations" -> {String[1]@5157} ["dubbo-provider.xml"]
    "reader" -> {Class@3159} "interface org.springframework.beans.factory.support.BeanDefinitionReader"
    "value" -> {String[1]@5159} ["dubbo-provider.xml"]
    
    将解析到的资源文件存储到了configClass的map容器中。
    
    接下来继续解析@Bean注解
    
    在解析完毕后,将解析到保存解析内容的configClass添加到configurationClasses map类型容器中。
    
    随后调用this.deferredImportSelectorHandler.process()对importSelector进行解析。
    其中,ConfigurationClassParser有多个导入类的内部类
    

    class ConfigurationClassParser {

    private static class ImportStack extends ArrayDeque<ConfigurationClass> implements ImportRegistry {
    

    }

    private class DeferredImportSelectorHandler {
    

    }
    private class DeferredImportSelectorGroupingHandler {
    }
    private static class DeferredImportSelectorHolder {
    }
    private static class DeferredImportSelectorGrouping {
    }
    private static class DefaultDeferredImportSelectorGroup implements Group {
    }
    }

    内部调用了DeferredImportSelectorGroupingHandler的register对deferredImports进行处理,
    在解析AutoConfigurationImportSlector的过程中,调用了一个getImports()方法,而这个方法底层调用的是SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()方法:
    
    ```java
    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
    		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
    				getBeanClassLoader());
    		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
    				+ "are using a custom packaging, make sure that file is correct.");
    		return configurations;
    	}
    }
    
    	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
                    //此处的cache中,已经缓存了spring.factories文件下要加载的不同类型的类
    		Map<String, List<String>> result = cache.get(classLoader);
    		if (result != null) {
    			return result;
    		}
    
    		result = new HashMap<>();
    		try {
    			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
    			while (urls.hasMoreElements()) {
    				URL url = urls.nextElement();
    				UrlResource resource = new UrlResource(url);
    				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    				for (Map.Entry<?, ?> entry : properties.entrySet()) {
    					String factoryTypeName = ((String) entry.getKey()).trim();
    					String[] factoryImplementationNames =
    							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
    					for (String factoryImplementationName : factoryImplementationNames) {
    						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
    								.add(factoryImplementationName.trim());
    					}
    				}
    			}
    
    			// Replace all lists with unmodifiable lists containing unique elements
    			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
    					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
    			cache.put(classLoader, result);
    		}
    		catch (IOException ex) {
    			throw new IllegalArgumentException("Unable to load factories from location [" +
    					FACTORIES_RESOURCE_LOCATION + "]", ex);
    		}
    		return result;
    	}
    

    此处我们只需要返回类型为org.springframework.boot.autoconfigure.EnableAutoConfiguration的类
    在加载完自动装配类后,后序调用了加载自动装配类的过滤器,默认包括3个

    org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
    org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
    org.springframework.boot.autoconfigure.condition.OnClassCondition,\
    org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
    
    

    这些过滤条件发挥作用是基于自动装配类上的注解条件,而在过滤的时候,默认是从spring下面的配置文件中,加载相关元注解信息,文件内容位于spring-autoconfigure-metadata.properties文件里面,默认加载了有773个。
    根据类名+过滤条件当做key 如:org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration+ConditionalOnClass=org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.ConditionalOnClass,
    在此项目中,进过条件过滤后,满足条件的配置类 Configuration有25个

    0 = "org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration"
    1 = "org.springframework.boot.autoconfigure.aop.AopAutoConfiguration"
    2 = "org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration"
    3 = "org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration"
    4 = "org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration"
    5 = "org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration"
    6 = "org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration"
    7 = "org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration"
    8 = "org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration"
    9 = "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"
    10 = "org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration"
    11 = "org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration"
    12 = "org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration"
    13 = "org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration"
    14 = "org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration"
    15 = "org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration"
    16 = "org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration"
    17 = "org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration"
    18 = "org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration"
    19 = "org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration"
    20 = "org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration"
    21 = "org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration"
    22 = "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration"
    23 = "org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration"
    24 = "com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration"
    

    此处着重分析DubboAutoConfiguration的加载,在对DubboAutoConfiguration配置类进行解析的时候,解析到 DubboAutoConfiguration包含三个Bean实例

    0 = {SimpleMethodMetadata@13417} "com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration.serviceAnnotationBeanPostProcessor(org.springframework.core.env.Environment)"
    1 = {SimpleMethodMetadata@13418} "com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration.relaxedDubboConfigBinder()"
    2 = {SimpleMethodMetadata@13419} "com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration.referenceAnnotationBeanPostProcessor()"
    

    至此,调用parse()解析完configurations之后,需要根据Configurations加载BeanDefinition,调用方法为

    	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;
    		}
    
    		if (configClass.isImported()) {
    			registerBeanDefinitionForImportedConfigurationClass(configClass);
    		}
    		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
    			loadBeanDefinitionsForBeanMethod(beanMethod);
    		}
    
    		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    	}
    
    	private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
    		registrars.forEach((registrar, metadata) ->
    				registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
    	}
    

    在解析dubbo_provider.xml时,使用了DefaultNamespaceHandlerResolver解析器,DefaultNamespaceHandlerResolver在初始化的时候,传入了handler的文件位置

    	/**
    	 * The location to look for the mapping files. Can be present in multiple JAR files.
    	 */
    	public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
    

    使用了自定义的NamespaceHandler进行解析node节点,通过获取对应的DubboBeanDefinitionParser,对对应node节点进行解析,并添加到BeanDefinitionMap容器中。
    在加载完BeanDefinition后,又调用了一些BeanFactoryPostProcessor,进行处理。

    内部调用会调用loadBeanDefinitionsFromRegistrars注册BeanDefinitions,内部使用ImportBeanDefinitionRegistrar注册BeanDefinition,调用了ImportBeanDefinitionRegistrar的继承类DubboConfigBindingsRegistrar来注册BeanDefinition

  • 相关阅读:
    处理视频流时可能出现的重复帧问题及解决办法
    shell脚本中cd命令无效
    C++教程之初识编程
    若干排序算法的Python实现方法及原理
    C/C++反三角函数使用注意
    ubuntu下安装pip install mysqlclient 报错 command "python setup.py egg_info" failed with error.....解决方案
    使用scrapy框架的monkey出现monkeypatchwarning: monkey-patching ssl after ssl...的解决办法
    机器学习之利用KNN近邻算法预测数据
    python数据分析的工具环境
    python代码实现经典排序算法
  • 原文地址:https://www.cnblogs.com/nangonghui/p/15568678.html
Copyright © 2011-2022 走看看