本小节介绍的是Spring从给定的扫描位置扫描到待加载的Bean,生成BeanDefinitionMap的过程
SpringBoot启动过程中使用的ApplicationContext是AnnotationConfigApplicationContext,而它初始化的时候会顺带初始化两个BeanDefinitionReader:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner,前者是可以直接通过给定的class注册Bean,后者则可以扫描给定目录下所有的目标Bean,下面着重介绍后者扫描Bean组件的过程。
ClassPathBeanDefinitionScanner扫描的入口是public int scan(String... basePackages),而真正做事情的是protected Set doScan(String... basePackages)方法,代码如下:
/**<br> * Perform a scan within the specified base packages,<br> * returning the registered bean definitions.<br> * <p>This method does <i>not</i> register an annotation config processor<br> * but rather leaves this up to the caller.<br> * @param basePackages the packages to check for annotated classes<br> * @return set of beans registered if any for tooling registration purposes (never {@code null})<br> */<br>protected Set<BeanDefinitionHolder> doScan(String... basePackages) {<br> Assert.notEmpty(basePackages, "At least one base package must be specified");<br> Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();<br> for (String basePackage : basePackages) {<br> // 找到basePackage下的所有候选组件,这里只是把classname赋值给了BeanDefinition<br> Set<BeanDefinition> candidates = findCandidateComponents(basePackage);<br> for (BeanDefinition candidate : candidates) {<br> // 获取组件的scope,默认是单例的<br> ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);<br> candidate.setScope(scopeMetadata.getScopeName());<br> // 获取beanname<br> String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);<br> if (candidate instanceof AbstractBeanDefinition) {<br> postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);<br> }<br> // 处理通用的注解<br> if (candidate instanceof AnnotatedBeanDefinition) {<br> AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);<br> }<br> // 最后再对BeanDefinition做检查,看下是否有重名的<br> if (checkCandidate(beanName, candidate)) {<br> BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);<br> definitionHolder =<br> AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);<br> beanDefinitions.add(definitionHolder);<br> registerBeanDefinition(definitionHolder, this.registry);<br> }<br> }<br> }<br> return beanDefinitions;<br> }
复制代码
下面将以上部分代码展开去讲
1.1 扫描包下面的所有组件
即对应findCandidateComponents方法的操作,该方法如下:
/**<br> * Scan the class path for candidate components.<br> * @param basePackage the package to check for annotated classes<br> * @return a corresponding Set of autodetected bean definitions<br> */<br> public Set<BeanDefinition> findCandidateComponents(String basePackage) {<br> if (this.componentsIndex != null && indexSupportsIncludeFilters()) {<br> return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);<br> }<br> else {<br> return scanCandidateComponents(basePackage);<br> }<br> }
/**<br> * Determine whether the given class does not match any exclude filter<br> * and does match at least one include filter.<br> * @param metadataReader the ASM ClassReader for the class<br> * @return whether the class qualifies as a candidate component<br> */<br> protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {<br> for (TypeFilter tf : this.excludeFilters) {<br> if (tf.match(metadataReader, getMetadataReaderFactory())) {<br> return false;<br> }<br> }<br> for (TypeFilter tf : this.includeFilters) {<br> if (tf.match(metadataReader, getMetadataReaderFactory())) {<br> return isConditionMatch(metadataReader);<br> }<br> }<br> return false;<br> }
判断扫描到的组件是否是正常的类
这里是有一套逻辑,因为一些内部类、抽象类、接口编译之后也会生成class文件,而这些文件到这一步是没有被过滤的,这里涉及到一个概念,说类是不是独立的,注释中是这么说的:
Determine whether the underlying class is independent, i.e. whether it is a top-level class or a nested class (static inner class) that can be constructed independently of an enclosing class.
即不依赖其他类也能正常被构建,因为后面扫描完成,有一个很重要的步骤,是实例化,而那些非静态的内部类、接口、抽象类是不能被实例化的,故这里排除在外。
try {<br> // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.<br> Object bean = resolveBeforeInstantiation(beanName, mbdToUse);<br> if (bean != null) {<br> return bean;<br> }<br>}<br>catch (Throwable ex) {<br> throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,<br> "BeanPostProcessor before instantiation of bean failed", ex);<br>}
/**<br> * Apply before-instantiation post-processors, resolving whether there is a<br> * before-instantiation shortcut for the specified bean.<br> * @param beanName the name of the bean<br> * @param mbd the bean definition for the bean<br> * @return the shortcut-determined bean instance, or {@code null} if none<br> */<br>@Nullable<br>protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {<br> Object bean = null;<br> if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {<br> // Make sure bean class is actually resolved at this point.<br> if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {<br> Class<?> targetType = determineTargetType(beanName, mbd);<br> if (targetType != null) {<br> bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);<br> if (bean != null) {<br> bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);<br> }<br> }<br> }<br> mbd.beforeInstantiationResolved = (bean != null);<br> }<br> return bean;<br>}
/**<br> * Actually create the specified bean. Pre-creation processing has already happened<br> * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.<br> * <p>Differentiates between default bean instantiation, use of a<br> * factory method, and autowiring a constructor.<br> * @param beanName the name of the bean<br> * @param mbd the merged bean definition for the bean<br> * @param args explicit arguments to use for constructor or factory method invocation<br> * @return a new instance of the bean<br> * @throws BeanCreationException if the bean could not be created<br> * @see #instantiateBean<br> * @see #instantiateUsingFactoryMethod<br> * @see #autowireConstructor<br> */<br>protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)<br> throws BeanCreationException {<br><br> // Instantiate the bean.<br> BeanWrapper instanceWrapper = null;<br> if (mbd.isSingleton()) {<br> instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);<br> }<br> if (instanceWrapper == null) {<br> instanceWrapper = createBeanInstance(beanName, mbd, args);<br> }<br> Object bean = instanceWrapper.getWrappedInstance();<br> Class<?> beanType = instanceWrapper.getWrappedClass();<br> if (beanType != NullBean.class) {<br> mbd.resolvedTargetType = beanType;<br> }<br><br> // 调用MergedBeanDefinitionPostProcessor中的postProcessMergedBeanDefinition<br> // Allow post-processors to modify the merged bean definition.<br> synchronized (mbd.postProcessingLock) {<br> if (!mbd.postProcessed) {<br> try {<br> applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);<br> }<br> catch (Throwable ex) {<br> throw new BeanCreationException(mbd.getResourceDescription(), beanName,<br> "Post-processing of merged bean definition failed", ex);<br> }<br> mbd.postProcessed = true;<br> }<br> }<br><br> // Eagerly cache singletons to be able to resolve circular references<br> // even when triggered by lifecycle interfaces like BeanFactoryAware.<br> boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&<br> isSingletonCurrentlyInCreation(beanName));<br> if (earlySingletonExposure) {<br> if (logger.isTraceEnabled()) {<br> logger.trace("Eagerly caching bean '" + beanName +<br> "' to allow for resolving potential circular references");<br> }<br> addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));<br> }<br><br> // Initialize the bean instance.<br> Object exposedObject = bean;<br> try {<br> populateBean(beanName, mbd, instanceWrapper);<br> exposedObject = initializeBean(beanName, exposedObject, mbd);<br> }<br> catch (Throwable ex) {<br> if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {<br> throw (BeanCreationException) ex;<br> }<br> else {<br> throw new BeanCreationException(<br> mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);<br> }<br> }<br><br> if (earlySingletonExposure) {<br> Object earlySingletonReference = getSingleton(beanName, false);<br> if (earlySingletonReference != null) {<br> if (exposedObject == bean) {<br> exposedObject = earlySingletonReference;<br> }<br> else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {<br> String[] dependentBeans = getDependentBeans(beanName);<br> Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);<br> for (String dependentBean : dependentBeans) {<br> if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {<br> actualDependentBeans.add(dependentBean);<br> }<br> }<br> if (!actualDependentBeans.isEmpty()) {<br> throw new BeanCurrentlyInCreationException(beanName,<br> "Bean with name '" + beanName + "' has been injected into other beans [" +<br> StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +<br> "] in its raw version as part of a circular reference, but has eventually been " +<br> "wrapped. This means that said other beans do not use the final version of the " +<br> "bean. This is often the result of over-eager type matching - consider using " +<br> "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");<br> }<br> }<br> }<br> }<br><br> // Register bean as disposable.<br> try {<br> registerDisposableBeanIfNecessary(beanName, bean, mbd);<br> }<br> catch (BeanDefinitionValidationException ex) {<br> throw new BeanCreationException(<br> mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);<br> }<br><br> return exposedObject;<br>}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the<br>// state of the bean before properties are set. This can be used, for example,<br>// to support styles of field injection.