Spring-容器的扫描器相关源码

首先看创建一个Spring容器的代码:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

源码:
/**
 * Create a new AnnotationConfigApplicationContext that needs to be populated
 * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
 */
public AnnotationConfigApplicationContext() {
	StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
	// 额外会创建StandardEnvironment
	this.reader = new AnnotatedBeanDefinitionReader(this);
	createAnnotatedBeanDefReader.end();
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

StartupStep是什么?

StartupStep是Spring5.3版本新增的,有两个实现类:DefaultStartupStep和FlightRecorderStartupStep

默认使用的是DefaultStartupStep,其实里面什么事情都没有做

FlightRecorderStartupStep使用了jdk9还是11以后的一个新特性,叫JFR

JFR简述:在jdk层面,提供的java程序,在生产运行过程中可以监控的一种机制,就像飞机的黑盒子,记录运行速度、性能

注意:这里不是Spring内部提供的牛逼功能,而是Spring利用jdk新特性的一个点,例如记录执行步骤的时间

了解JFR,可参考文章:深度探索JFR - JFR详细介绍与生产问题定位落地 - 1. JFR说明与启动配置 - 知乎

创建一个Spring容器主要做了什么事情呢?

扫描、创建非懒加载的单例Bean

接下来再看ClassPathBeanDefinitionScanner的扫描方法:(重点关注doScan方法)

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

	private final BeanDefinitionRegistry registry;
	
	... ...

	/**
	 * Perform a scan within the specified base packages,
	 * returning the registered bean definitions.
	 * 

This method does not register an annotation config processor * but rather leaves this up to the caller. * @param basePackages the packages to check for annotated classes * @return set of beans registered if any for tooling registration purposes (never {@code null}) */ protected Set doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { // 核心扫描逻辑,得到BeanDefinition Set candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { // 解析Scope注解,单例还是原型设置进来 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // @Component注解有没有指定名字,指定直接返回,没有指定构造默认的 // 默认根据类的短名生成。大部分情况首字母小写,但是类名前两个字母都是大写就直接返回类名 // 举例默认情况:UserService - userService; ABTest - ABTest String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { // 遍历出来的BeanDefinition设置默认值 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { // 解析@Lazy、@Primary、@DependsOn、@Role、@Description,设置给BeanDefinition对应的属性 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 检查Spring容器中是否已经存在该beanName 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; } /** * Scan the class path for candidate components. * @param basePackage the package to check for annotated classes * @return a corresponding Set of autodetected bean definitions */ public Set findCandidateComponents(String basePackage) { if (this.componentsIndex != null && indexSupportsIncludeFilters()) { return addCandidateComponentsFromIndex(this.componentsIndex, basePackage); } else { return scanCandidateComponents(basePackage); } } private Set scanCandidateComponents(String basePackage) { Set candidates = new LinkedHashSet<>(); try { // 获取basePackage下所有的文件资源,匹配所有的class文件 String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; // 资源,class文件的File对象 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 { // 类的元数据读取器,类的注解信息、名字、是不是抽象、实现的接口名字、父类等 // 底层使用的ASM技术,metadataReader相当于类的一个代表 MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); // excludeFilters、includeFilters判断 // includeFilters判断:默认添加一个@Component注解(创建扫描器时添加的) 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 (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; } /** * Determine whether the given class does not match any exclude filter * and does match at least one include filter. * @param metadataReader the ASM ClassReader for the class * @return whether the class qualifies as a candidate component */ protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { // 如果传入的类和任何一个排除过滤器匹配了,就返回false,表示不是一个Bean for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return false; } } // 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional for (TypeFilter tf : this.includeFilters) { // 有@Component注解匹配 if (tf.match(metadataReader, getMetadataReaderFactory())) { return isConditionMatch(metadataReader); } } return false; } /** * Determine whether the given class is a candidate component based on any * {@code @Conditional} annotations. * @param metadataReader the ASM ClassReader for the class * @return whether the class qualifies as a candidate component */ private boolean isConditionMatch(MetadataReader metadataReader) { if (this.conditionEvaluator == null) { this.conditionEvaluator = new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver); } return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata()); } /** * Determine if an item should be skipped based on {@code @Conditional} annotations. * The {@link ConfigurationPhase} will be deduced from the type of item (i.e. a * {@code @Configuration} class will be {@link ConfigurationPhase#PARSE_CONFIGURATION}) * @param metadata the meta data * @return if the item should be skipped */ public boolean shouldSkip(AnnotatedTypeMetadata metadata) { return shouldSkip(metadata, null); } /** * Determine if an item should be skipped based on {@code @Conditional} annotations. * @param metadata the meta data * @param phase the phase of the call * @return if the item should be skipped */ public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) { // 没有@Conditional注解,就不要跳过,当前类是一个Bean(有@Component,没有@Conditional) if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) { return false; } if (phase == null) { if (metadata instanceof AnnotationMetadata && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) { return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION); } return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN); } List conditions = new ArrayList<>(); for (String[] conditionClasses : getConditionClasses(metadata)) { for (String conditionClass : conditionClasses) { Condition condition = getCondition(conditionClass, this.context.getClassLoader()); conditions.add(condition); } } AnnotationAwareOrderComparator.sort(conditions); for (Condition condition : conditions) { ConfigurationPhase requiredPhase = null; if (condition instanceof ConfigurationCondition) { requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase(); } if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) { return true; } } return false; } /** * Create a new ScannedGenericBeanDefinition for the class that the * given MetadataReader describes. * @param metadataReader the MetadataReader for the scanned target class */ public ScannedGenericBeanDefinition(MetadataReader metadataReader) { Assert.notNull(metadataReader, "MetadataReader must not be null"); this.metadata = metadataReader.getAnnotationMetadata(); // 这里只是把className设置到BeanDefinition中 setBeanClassName(this.metadata.getClassName()); setResource(metadataReader.getResource()); } /** * Specify the bean class name of this bean definition. */ @Override public void setBeanClassName(@Nullable String beanClassName) { // 把className设置到BeanDefinition的beanClass属性,beanClass是Object类型 this.beanClass = beanClassName; } /** * Determine whether the given bean definition qualifies as candidate. *

The default implementation checks whether the class is not an interface * and not dependent on an enclosing class. *

Can be overridden in subclasses. * @param beanDefinition the bean definition to check * @return whether the bean definition qualifies as a candidate component */ protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { AnnotationMetadata metadata = beanDefinition.getMetadata(); // 不是独立的,不能成为Bean(如果是一个顶级类或者静态内部类,那么就是独立的) // isConcrete:!(是接口||是抽象类),说白了就不是接口,也不是抽象类 // 是抽象类,但是类里面有@Lookup注解修饰的方法,可以成为Bean // 总结:独立的;不是接口也不是抽象类;是抽象类,并且类内方法有@Lookup注解。三种情况是Bean return (metadata.isIndependent() && (metadata.isConcrete() || (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))); } /** * Check the given candidate's bean name, determining whether the corresponding * bean definition needs to be registered or conflicts with an existing definition. * @param beanName the suggested name for the bean * @param beanDefinition the corresponding bean definition * @return {@code true} if the bean can be registered as-is; * {@code false} if it should be skipped because there is an * existing, compatible bean definition for the specified name * @throws ConflictingBeanDefinitionException if an existing, incompatible * bean definition has been found for the specified name */ protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException { if (!this.registry.containsBeanDefinition(beanName)) { return true; } BeanDefinition existingDef = this.registry.getBeanDefinition(beanName); BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition(); if (originatingDef != null) { existingDef = originatingDef; } // 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。 if (isCompatible(beanDefinition, existingDef)) { return false; } throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName + "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " + "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]"); } ... ... }

思考:BeanDefinitionRegistry能不能用DefaultListableBeanFactory替换?

DefaultListableBeanFactory是BeanDefinitionRegistry的重要实现类,功能上可以替换但是没有必要。

这里扫描器主要的功能是:把扫描得到的BeanDefinition注册到Spring容器里面去,注册功能是BeanDefinitionRegistry这个接口提供的。DefaultListableBeanFactory确实有注册的功能,但是DefaultListableBeanFactory还有很多其他的功能,这里并不需要。单一职责

实际运行的时候registry属性的值就是DefaultListableBeanFactory对象

注意:有@Component注解不一定是一个Bean。如果还有@Conditional注解,就要看条件是否匹配,条件匹配了才是一个Bean,条件不匹配就不是一个Bean(@Conditional注解指定的类需要实现Condition接口,并且重写matches方法,matches方法返回true表示匹配,返回false不匹配)

BeanDefinition的beanClass属性为什么是Object类型?而不是Class?

扫描到setBeanClassName方法这里时,是通过ASM技术去解析这个类,并没有去加载这个类,只是把Bean的名字设置给BeanDefinition的beanClass属性。等真正的去加载这个Bean时,才会得到Class对象,再把这个对象赋值给beanClass属性。这里使用Object就是考虑到两种情况:最开始赋值的是Bean的名字,加载后赋值Class对象

你可能感兴趣的:(spring,java)