Spring源码解读(十二)通过包路径扫描Bean——ClassPathBeanDefinitionScanner

前言

spring解析Bean通常通过 读取xml文件 扫码注解 两种方式进行。在 Spring源码解读(二)Bean创建过程之解析——BeanDefinition 中分析了通过读取xml文件解析得到BeanDefinnition,这篇博文再来分析扫描指定包路径下的注解解析Bean.

类的继承关系

扫描指定包下的注解标注的bean是由ClassPathBeanDefinitionScanner实现的。

up-814c06be6047b900e3073fbc2a0ceb4d856.png

程序入口

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.lsz.demo");
Object bean = ctx.getBean("");

使用AnnotationConfigApplicationContext,通过它的边长参数的构造方法, 传入要扫描的报名构建上下文对象。

默认情况下会为该上下文对象指定ClassPathBeanDefinitionScanner扫描器。

	public AnnotationConfigApplicationContext(String... basePackages) {
		/**
		 * 先调用无参构造方法
		 * 		this.reader = new AnnotatedBeanDefinitionReader(this);
		 * 		this.scanner = new ClassPathBeanDefinitionScanner(this);
		 * 	无参构造方法内就是bean的读取器和扫描器
		 */
		this();
		// 调用自己的scan方法,扫码所需的bean
		scan(basePackages);
		// 这里父类org.springframework.context.support.AbstractApplicationContext的方法
		// 用于刷新整个spring上下文信息,是spring的核心内容
		refresh();
	}

	public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

创建ClassPathBeanDefinitionScanner

最终执行的构造方法:

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment, @Nullable ResourceLoader resourceLoader) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		this.registry = registry;

		if (useDefaultFilters) {
			// 注册默认的过滤器,调用父类ClasspathScanningCandidateComponentProvider的方法
			registerDefaultFilters();
		}
		// 环境参数
		setEnvironment(environment);
		// 系统资源
		setResourceLoader(resourceLoader);
	}

由上面的继承关系可以得知ClassPathBeanDefinitionScanner间接实现了 EnvironmentCapable 和 ResourceLoaderAware ,从而能到拿到环境参数和系统资源加载器,很好理解,这里分析下父类的 registerDefaultFilters方法,主要主要就是添加需要扫描的过滤去,如我们这里加入的我们常见的@Component注解和javax.annotation.ManagedBean、javax.inject.Named,后面两个时非必须的。


	/**
	 * 需要扫描的过滤器
	 */
	private final List<TypeFilter> includeFilters = new ArrayList<>();

	/**
	 * 排除掉的过滤器
	 */
	private final List<TypeFilter> excludeFilters = new ArrayList<>();



	protected void registerDefaultFilters() {
		// 添加需要扫描的注解 @Component
		// 因为 @Controller、@Service、@Repository 都被 @Component 注解标注,所以隐私的包含了这三个注解
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
			// 添加需要扫描的注解 @ManagedBean
			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 {
			// 添加需要扫描的注解 @Named
			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.
		}
	}

进行扫描处理

这个方法内主要完成部分操作 扫描指定包路径下的bean和注册注解配置Bean的处理器。

	public int scan(String... basePackages) {
		// 这就是bean注册表的大小,也就是BeanFactory中map的大小
		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

		// 执行扫描
		doScan(basePackages);

		// Register annotation config processors, if necessary.
		if (this.includeAnnotationConfig) {
			// 注册注解配置处理器
			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
		}

		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
	}

不知大家有没有发现一个规律,spring源码中的执行其真是含义的代码都是以“do”开头的,比如getBean()方法中会调用doGetBean(),createBean方法中会调用doCreateBean,这里也是一样scan方法中调用doScan方法。有了这个规律,读剩下的源码的时候能更快的定位到核心位置。

执行扫描指定的包并注册

	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();

		// 遍历变长参数,处理多个包下bean
		for (String basePackage : basePackages) {
			// 查找包路径下的bean,将其转换为BeanDefinition
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				// 解析bean的scope属性
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				// 生成beanName
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					// 如果是AbstractBeanDefinition,给这个装饰类赋默认值
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					// 如果是AnnotatedBeanDefinition(有注解的类)
					// 把注解设置到装饰类中
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				// 检查beanName是否重复有冲突
				if (checkCandidate(beanName, candidate)) {
					// 构建BeanDefinitionHolder
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					// 应用作用域代理模式
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					// 注册Bean
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

查找到包路径下的bean,并转换为BeanDifinition

这个方法内分为普通处理和对@Indexed的处理。对@Indexed的处理是spring5的新特性,目的是为了提升spring启动的性能。


	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
			// 对 @Indexed 注册处理
			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
		}
		else {
			// 普通逻辑处理
			return scanCandidateComponents(basePackage);
		}
	}

普通处理 scanCandidateComponents

	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// 包搜索路径   classpath*:xxx.**.*.class
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			// 将class文件转换为resource对象
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			// 遍历resource,将resource转换为ScannedGenericBeanDefinition
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				try {
					// 读取resource的元数据,也就是class的信息
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
					// 根据excludeFilters和includeFilters判断是否符合处理条件
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setSource(resource);
						// 判断是否可以被实例化, 确定给定的 bean 定义是否有资格作为候选。 排除接口类等等
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							// 添加到候选bean集合中
							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;
	}

对@Indexed的处理 addCandidateComponentsFromIndex

关于对@Indexed的实现细节上,涉及到很多其他的东西,这里暂时不展开。

private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			Set<String> types = new HashSet<>();
			// 遍历过滤器,找出满足条件的的bean
			for (TypeFilter filter : this.includeFilters) {
				// 获取过滤器的名字。
				String stereotype = extractStereotype(filter);
				if (stereotype == null) {
					throw new IllegalArgumentException("Failed to extract stereotype from " + filter);
				}
				// 在过滤器中添加与指定构造型关联的候选类型。
				types.addAll(index.getCandidateTypes(basePackage, stereotype));
			}
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (String type : types) {
				// 读取resource的元数据,也就是class的信息
				MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
				// 根据excludeFilters和includeFilters判断是否符合处理条件
				if (isCandidateComponent(metadataReader)) {
					ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
					sbd.setSource(metadataReader.getResource());
					// 判断是否可以被实例化, 确定给定的 bean 定义是否有资格作为候选。 排除接口类等等
					if (isCandidateComponent(sbd)) {
						if (debugEnabled) {
							logger.debug("Using candidate component class from index: " + type);
						}
						// 添加到候选bean集合中
						candidates.add(sbd);
					}
					else {
						if (debugEnabled) {
							logger.debug("Ignored because not a concrete top-level class: " + type);
						}
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because matching an exclude filter: " + type);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

对AbstractBeanDefinition处理

	protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
		// 填充默认值
		beanDefinition.applyDefaults(this.beanDefinitionDefaults);
		if (this.autowireCandidatePatterns != null) {
			// 如果设置了autowireCandidatePatterns自动装配候选模式,则按照其跪着设置bean的AutowireCandidate
			beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
		}
	}

对AnnotatedBeanDefinition处理

对通用的注解解析,然后填充到装饰类BeanDefinition中。

	static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
		if (lazy != null) {
			abd.setLazyInit(lazy.getBoolean("value"));
		}
		else if (abd.getMetadata() != metadata) {
			lazy = attributesFor(abd.getMetadata(), Lazy.class);
			if (lazy != null) {
				abd.setLazyInit(lazy.getBoolean("value"));
			}
		}

		if (metadata.isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}
		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
		if (dependsOn != null) {
			abd.setDependsOn(dependsOn.getStringArray("value"));
		}

		AnnotationAttributes role = attributesFor(metadata, Role.class);
		if (role != null) {
			abd.setRole(role.getNumber("value").intValue());
		}
		AnnotationAttributes description = attributesFor(metadata, Description.class);
		if (description != null) {
			abd.setDescription(description.getString("value"));
		}
	}

检查BeanName

	protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
		if (!this.registry.containsBeanDefinition(beanName)) {
			// 注册表中不包含这个beanName 直接返回ture
			return true;
		}
		BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
		BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
		if (originatingDef != null) {
			existingDef = originatingDef;
		}
		// 当前这个beanName已经存在了,判断给定的新 BeanDefinition 是否与给定的现有BeanDefinition兼容。
		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() + "]");
	}

对BeanDefinition代理模式处理

	static BeanDefinitionHolder applyScopedProxyMode(
			ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
		// 获取代理模式
		ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
		/**
		 * ScopedProxyMode 存在四个类型
		 * DEFAULT、NO :不要创建范围代理
		 * INTERFACES:JDK动态代理
		 * TARGET_CLASS:CGLIB代理
		 */
		if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
			// 代理默认如果为NO, 不需要代理直接返回
			return definition;
		}
		boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
		// 为提供的目标 bean 生成一个作用域代理,使用内部名称注册目标 bean 并在作用域代理上设置“targetBeanName”。
		return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
	}

将BeanDefinition注册到BeanFactroy的注册表

BeanDefinitionReaderUtils#registerBeanDefinition这个方法在 Spring源码解读(三)Bean创建过程之注册——DefaultListableBeanFactory 中已经分析过了。

	protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值