一、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) {//获取路径下的所有BeanDefinition//具体看代码V1.1Set<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//并设置给当前beanDefinitionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查Spring容器中是否已经存在该beanName//见的代码V1.7if (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) {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.2if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断//创建BeanDefinition,并将className赋值给BeanClassScannedGenericBeanDefinition 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.3for (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对应的AnnotationTypeFilterthis.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());}↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓@Overridepublic 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的名字
@Overridepublic String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {if (definition instanceof AnnotatedBeanDefinition) {// 获取注解所指定的beanNameString 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的名字并没有被注册过,返回trueif (!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 twicenewDefinition.equals(existingDefinition)); // scanned equivalent class twice}