Spring-包扫描

 一、doScan包扫描

V1.0 doScan
流程图

包扫描

1、根据配置的包扫名路径构建出Beandefinition

2、循环构建出的BeanDefinition集合

3、获取ScopeMetadata元数据读取器

4、对beandefinition进行赋值

5、返回所有的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) {
			//获取路径下的所有BeanDefinition
            //具体看代码V1.1
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

			for (BeanDefinition candidate : candidates) {
                //设置bean的作用范围 默认 singleton 
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
                //对beanDefinition设置bean的名字
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                //对beanDefinition设置默认值
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					// 解析@Lazy、@Primary、@DependsOn、@Role、@Description
                    //并设置给当前beanDefinition
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}

				// 检查Spring容器中是否已经存在该beanName
                //见的代码V1.7
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);

					// 注册,将beanName作为key beanDefinition作为value存入beanDefinitionMap中
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}
V1.1 isCandidateComponent

判断当前类是否需要当作bean进行处理

	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		//componentsIndex 对应META-INF下的spring.components文件,里面的内容全包名类名作为key,注解名作为value
		//加入该文件后,就会走这边的逻辑,只扫描配置好的类,可以减少扫描时间
		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
		}
		else {
			return scanCandidateComponents(basePackage);
		}
	}
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓	

	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// 获取basePackage下所有的文件资源  CLASSPATH_ALL_URL_PREFIX = "classpath*:"
			// DEFAULT_RESOURCE_PATTERN = "**/*.class";
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			//获取包路径下的所有的.class文件
			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);
						// excludeFilters、includeFilters判断
                        // 代码V1.2
						if (isCandidateComponent(metadataReader)) { // @Component--
            >includeFilters判断
            //创建BeanDefinition,并将className赋值给BeanClass
							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;
	}
V1.2 isCandidateComponent

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

		// 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional
		//spring启动的时候会自动将@Component注解加入includeFilters中
		// 具体看代码 V1.3
		for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				//当类满足Component注解或其他设定为需要加载Bean的注解
				// 仍需要判断是否满足条件@Conditional注解中包含的条件
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

V1.3 registerDefaultFilters

spring在启动的时候就会往includeFilters中加入component注解

protected void registerDefaultFilters() {

		// 注册@Component对应的AnnotationTypeFilter
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));

		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

		try {
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
			logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
		}

		try {
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
			logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}
V1.4 ScannedGenericBeanDefinition

对扫描到的BeanDefinition进行赋值,但是此时只是将className赋值到BeanDefinition中,因为还没有创建该类

	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());
	}
	↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
	@Override
	public void setBeanClassName(@Nullable String beanClassName) {
		this.beanClass = beanClassName;
	}
V1.5 isCandidateComponent

二次判断类是否可独立实例化对象,内部类或者接口,抽象类都会对应生成一个.class文件,但是这些文件部分是不能够实例化的,不可以生成bean,所以在生成BeanDefinition之前需要进行过滤判断

	/**
	 *确定给定的bean定义是否符合候选条件。
	 *默认实现检查类是否不是接口并且不依赖于封闭类且可以在子类中重写
	 *(即
	 * 1、是否是顶级类或者静态内部类等独立类,
	 * 2、不是接口并且不是抽象类,
	 * 3、如果是抽象类,含有至少一个方法实现Lookup注解)
	 *
	 */
	protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
		AnnotationMetadata metadata = beanDefinition.getMetadata();
		return (metadata.isIndependent() && (metadata.isConcrete() ||
				(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
	}
	
	↓↓↓↓↓↓↓↓↓↓
	default boolean isConcrete() {
		//判断不是接口并且不是抽象类
		return !(isInterface() || isAbstract());
	}

V1.6 generateBeanName

获取bean的名字

	@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
		if (definition instanceof AnnotatedBeanDefinition) {
			// 获取注解所指定的beanName
			String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
			if (StringUtils.hasText(beanName)) {
				// Explicit bean name found.
				return beanName;
			}
		}
		// 如果注解中没有指定bean的名称,则采用默认名称
		return buildDefaultBeanName(definition, registry);
	}
	↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
	protected String buildDefaultBeanName(BeanDefinition definition) {
		String beanClassName = definition.getBeanClassName();
		Assert.state(beanClassName != null, "No bean class name set");
		//获取sortName
		//如果beanClassName长度小于0返回空
		//如果beanClassName的第一个第二个字母都是大写,则返回beanClassName
		//否则将beanClassName的第一个字母设为小写后,返回
		String shortClassName = ClassUtils.getShortName(beanClassName);
		return Introspector.decapitalize(shortClassName);
	}

V1.7 checkCandidate

	protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
		//当前bean的名字并没有被注册过,返回true
		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() + "]");
	}

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
	protected boolean isCompatible(BeanDefinition newDefinition, BeanDefinition existingDefinition) {
		//判断beanDefinition是否是统一类型,如果是,代表多次扫描统一相同的bean,而非不同的bean使用相同的名称
		//可兼容,但是跳过本次处理
		return (!(existingDefinition instanceof ScannedGenericBeanDefinition) ||  // explicitly registered overriding bean
				(newDefinition.getSource() != null && newDefinition.getSource().equals(existingDefinition.getSource())) ||  // scanned same file twice
				newDefinition.equals(existingDefinition));  // scanned equivalent class twice
	}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值