在上一篇文章中一个简单的例子来探寻Spring实例化bean执行源码的主脉络(一):this()方法,我们跟踪源码还是不知道怎么解析配置类,只是走完了this()方法,跟配置类感觉没有一毛钱的关系,这里我们大概了解了一下this做了啥?
1、初始化了AnnotationConfigApplicationContext对象
2、初始化了AnnotationConfigApplicationContext的父对象GenericApplicationContext
3、GenericApplicationContext对象里面初始化了一个beanFactory成员变量,对象为DefaultListableBeanFactory
4、初始化了一个reader:AnnotatedBeanDefinitionReader
5、初始化reder的过程中把几个后置处理器比如internalPersistenceAnnotationProcessor和internalAutowiredAnnotationProcessor等放到了DefaultListableBeanFactory中的beanDefinitionMap中,key为bean的名称,值为beanDefinition放的应该是这些后置处理器的相关类定义
6、初始化了一个scanner:ClassPathBeanDefinitionScanner
推测所有要加载为bean的类都将放到beanDefinitionMap中!
先在我们继续看看第二个方法register(componentClasses);
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {this();register(componentClasses);refresh();}
执行register(componentClasses);方法
这里我们终于看到了我们传入的参数,那大概可以推测,应该是在这个方法里面对我们的配置类进行初始化的,由上一篇文章我们可以合理推测,配置类也会放到beanDefinitionMap中,看看是不是这样,跟踪代码进去。
/*** Register one or more component classes to be processed.* <p>Note that {@link #refresh()} must be called in order for the context* to fully process the new classes.* @param componentClasses one or more component classes — for example,* {@link Configuration @Configuration} classes* @see #scan(String...)* @see #refresh()*/@Overridepublic void register(Class<?>... componentClasses) {Assert.notEmpty(componentClasses, "At least one component class must be specified");this.reader.register(componentClasses);}
看注释说是注册一个或者多个要处理的组件类,大概猜测一下,这里应该是注册类,而不是生成bean,所以可能是解析配置类SpringConfiguration,然后解析配置类上的@ComponentScan(basePackages = “com.suibibk.spring”),然后把com.suibibk.spring文件加下的加了@Component注解的类全部都注册进来(猜测失败,值注册了SpringConfiguration),注册到哪里呢?大胆推测注册到DefaultListableBeanFactor的beanDefinitionMap中去,好让后面实例化bean,当然推测不一定正确,不过好的框架一定会有重充足的注释,我们一定要根据注释和变量命名来推测理解源码!这里然后u调用的是
this.reader.register(componentClasses);
reader就是在this()方法里面初始化的AnnotationConfigApplicationContext对象的AnnotatedBeanDefinitionReader,继续跟进去
public void register(Class<?>... componentClasses) {for (Class<?> componentClass : componentClasses) {registerBean(componentClass);}}
这里的意思是可能会传入多个配置类,然后循环处理所有的配置类调用registerBean(componentClass);方法,跟踪进去
/*** Register a bean from the given bean class, deriving its metadata from* class-declared annotations.* @param beanClass the class of the bean*/public void registerBean(Class<?> beanClass) {doRegisterBean(beanClass, null, null, null, null);}
方法的注释的意思是说从给定的bean类中注册一个bean,然后从类声名注解中得到他的元数据,是不是有点不知所云,不过大概可以知道还是解析配置类,继续跟进去
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,@Nullable BeanDefinitionCustomizer[] customizers) {AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}abd.setInstanceSupplier(supplier);ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {for (Class<? extends Annotation> qualifier : qualifiers) {if (Primary.class == qualifier) {abd.setPrimary(true);}else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}if (customizers != null) {for (BeanDefinitionCustomizer customizer : customizers) {customizer.customize(abd);}}BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}
我们先看第一行代码
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
这里相当于把我们传来的配置类包装了一下,变成了AnnotatedGenericBeanDefinition对象,话说,具体有啥用我也不知道,因为我们就只传了第一个参数beanClass,所以后面的qualifiers和customizers都是null,直接跳过,然后执行到最后的代码
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
所料不差,就是把配置类注册到了DefaultListableBeanFactor的beanDefinitionMap中去,不过并没有对配置类的@ComponentScan进行解析,上面猜测失败,也就是说,register(componentClasses);方法只是对配置类进行了处理而已,其他啥都没有操作。
好吧,到这里我们已经看了this()和register(componentClasses)的源码,也知道了是在register注册了配置类,但是没有进行解析,看来一切都将在
refresh();
中水落石出,走起!
执行refresh();方法
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}
这个方法很长,我们一行行来分析,有些理解不了的就先跳过,毕竟我们只是为了找到主脉络,目的是知道spring在什么地方对配置类进行解析以及在什么地方进行初始化的。
先看第一行代码
prepareRefresh();
准备刷新?
/*** Prepare this context for refreshing, setting its startup date and* active flag as well as performing any initialization of property sources.*/protected void prepareRefresh() {// Switch to active.this.startupDate = System.currentTimeMillis();this.closed.set(false);this.active.set(true);if (logger.isDebugEnabled()) {if (logger.isTraceEnabled()) {logger.trace("Refreshing " + this);}else {logger.debug("Refreshing " + getDisplayName());}}// Initialize any placeholder property sources in the context environment.initPropertySources();// Validate that all properties marked as required are resolvable:// see ConfigurablePropertyResolver#setRequiredPropertiesgetEnvironment().validateRequiredProperties();// Store pre-refresh ApplicationListeners...if (this.earlyApplicationListeners == null) {this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);}else {// Reset local application listeners to pre-refresh state.this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);}// Allow for the collection of early ApplicationEvents,// to be published once the multicaster is available...this.earlyApplicationEvents = new LinkedHashSet<>();}
what?设置一些初始时间和活跃标志?大概浏览下应该是跟解析配置文件和初始bean什么的没有任何关系的,可以跳过!
咱们来看第二行代码
// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
告诉子类刷新内部的bean工厂,点进去看看
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();return getBeanFactory();}
@Overrideprotected final void refreshBeanFactory() throws IllegalStateException {if (!this.refreshed.compareAndSet(false, true)) {throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");}this.beanFactory.setSerializationId(getId());}
上面的代码是在GenericApplicationContext下,因为我们的AnnotationConfigApplicationContext继承的就是这个对象,这里只是简单的设置一些信息,我们再看 getBeanFactory()
/*** Return the single internal BeanFactory held by this context* (as ConfigurableListableBeanFactory).*/@Overridepublic final ConfigurableListableBeanFactory getBeanFactory() {return this.beanFactory;}
只是返回一个BeanFactory由前面我们知道,这里就是DefaultListableBeanFactor对象。我们继续看代码
// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);
对这个beanFactory做一些准备工作,我们看看准备了啥
/*** Configure the factory's standard context characteristics,* such as the context's ClassLoader and post-processors.* @param beanFactory the BeanFactory to configure*/protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.beanFactory.setBeanClassLoader(getClassLoader());beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);// BeanFactory interface not registered as resolvable type in a plain factory.// MessageSource registered (and found for autowiring) as a bean.beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// Register early post-processor for detecting inner beans as ApplicationListeners.beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// Detect a LoadTimeWeaver and prepare for weaving, if found.if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}// Register default environment beans.if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());}if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());}if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());}}
一大串,对就是准备了一大串,看不懂没关系,反正我们知道是在做一些准备工作,我们看看有哪些看得懂的,比如beanFactory.setBeanClassLoader(getClassLoader());设置类加载器,
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
加入一个Bean后置处理器,加入的是ApplicationContextAwareProcessor对象,我们知道前面在执行this()方法的时候也还加入了很多其它的后置处理器。其它的不看先,跟我的目标有区别,我是要找到什么地方解析配置类。我们看下一行
// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);
允许在上下文子类中对bean工厂进行后处理,点进去发现是一个空的方法,应该是模板方法为了让后面的子类实现然后对代码逻辑进行增强把。继续
// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);
在上下文中调用注册为bean的工厂处理器。额,看注释感觉是一个很重要的方法,难道一切都会在这里水落石出?
invokeBeanFactoryPostProcessors(beanFactory);方法
/*** Instantiate and invoke all registered BeanFactoryPostProcessor beans,* respecting explicit order if given.* <p>Must be called before singleton instantiation.*/protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}
实例化并调用所有注册的BeanFactoryPostProcessor,我们继续跟踪代码
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}else {regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();}
这个代码真的真的很长!我们根据方法的意思,大概可以看的出
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
才是主要的,调用bean定义注册后置处理器,其它我们不看先,
/*** Invoke the given BeanDefinitionRegistryPostProcessor beans.*/private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {postProcessor.postProcessBeanDefinitionRegistry(registry);}}
这里看不明白,继续
/*** Derive further bean definitions from the configuration classes in the registry.*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId = System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}this.registriesPostProcessed.add(registryId);processConfigBeanDefinitions(registry);}
从注册中心中的配置类派生进一步的bean定义,这里感觉有点苗头了,直接看
processConfigBeanDefinitions(registry);
/*** Build and validate a configuration model based on the registry of* {@link Configuration} classes.*/public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// Return immediately if no @Configuration classes were foundif (configCandidates.isEmpty()) {return;}// Sort by previously determined @Order value, if applicableconfigCandidates.sort((bd1, bd2) -> {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integer.compare(i1, i2);});// Detect any custom bean name generation strategy supplied through the enclosing application contextSingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry) registry;if (!this.localBeanNameGeneratorSet) {BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);if (generator != null) {this.componentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}}if (this.environment == null) {this.environment = new StandardEnvironment();}// Parse each @Configuration classConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());do {parser.parse(candidates);parser.validate();Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);candidates.clear();if (registry.getBeanDefinitionCount() > candidateNames.length) {String[] newCandidateNames = registry.getBeanDefinitionNames();Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));Set<String> alreadyParsedClasses = new HashSet<>();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&!alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}}while (!candidates.isEmpty());// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classesif (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());}if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {// Clear cache in externally provided MetadataReaderFactory; this is a no-op// for a shared cache since it'll be cleared by the ApplicationContext.((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();}}
构建和验证配置模型,
一开始
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();
从注册表中获取所有的候选名字
@Overridepublic String[] getBeanDefinitionNames() {String[] frozenNames = this.frozenBeanDefinitionNames;if (frozenNames != null) {return frozenNames.clone();}else {return StringUtils.toStringArray(this.beanDefinitionNames);}}
其实就是我们之前放进去的bean名称,再看后面的逻辑
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}
看方法名字就大概知道是什么检查是否是配置类,也就是加了@Configuration注解的类,通过调试验证了我的猜想,最后configCandidates中只有com.suibibk.spring.SpringConfiguration的信息。
// Parse each @Configuration classConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);
这里生成了一个解析器,我们到这里就可以猜想,后面肯定是对配置类开始进行解析处理了,果不奇然
do {parser.parse(candidates);parser.validate();...
接下来就是要准备来解析了。感觉这里又是一个重大的方法。
parser.parse(candidates);方法
ublic void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition();try {if (bd instanceof AnnotatedBeanDefinition) {parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}else {parse(bd.getBeanClassName(), holder.getBeanName());}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);}}this.deferredImportSelectorHandler.process();}
我们之前在注册配置类的时候开始有对配置类进行包装
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
而AnnotatedGenericBeanDefinition
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition
所以
if (bd instanceof AnnotatedBeanDefinition)
为true。进入到第一个
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
进行解析,参数为配置类的元数据和配置类名称
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);}
继续跟进去
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {return;}ConfigurationClass existingClass = this.configurationClasses.get(configClass);if (existingClass != null) {if (configClass.isImported()) {if (existingClass.isImported()) {existingClass.mergeImportedBy(configClass);}// Otherwise ignore new imported config class; existing non-imported class overrides it.return;}else {// Explicit bean definition found, probably replacing an import.// Let's remove the old one and go with the new one.this.configurationClasses.remove(configClass);this.knownSuperclasses.values().removeIf(configClass::equals);}}// Recursively process the configuration class and its superclass hierarchy.SourceClass sourceClass = asSourceClass(configClass, filter);do {sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);}while (sourceClass != null);this.configurationClasses.put(configClass, configClass);}
这里调试发现existingClass为null,话说我们也没有对配置类进行任何特殊处理,所以应该是null,直接看下面的方法
// Recursively process the configuration class and its superclass hierarchy.SourceClass sourceClass = asSourceClass(configClass, filter);
递归地处理配置类及其超类层次结构。我们这里就只有一个孤孤单单的配置类,所以这里面应该只有
com.suibibk.spring.SpringConfiguration
话说这个方法是用于那种有注解上有注解或者继承类为配置类的情况吧,这里不考虑那么多先,直接看
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
/*** Apply processing and build a complete {@link ConfigurationClass} by reading the* annotations, members and methods from the source class. This method can be called* multiple times as relevant sources are discovered.* @param configClass the configuration class being build* @param sourceClass a source class* @return the superclass, or {@code null} if none found or previously processed*/@Nullableprotected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass, filter);}// Process any @PropertySource annotationsfor (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);}else {logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}}// Process any @ComponentScan annotationsSet<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediatelySet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// Process any @Import annotationsprocessImports(configClass, sourceClass, getImports(sourceClass), filter, true);// Process any @ImportResource annotationsAnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// Process individual @Bean methodsSet<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfacesprocessInterfaces(configClass, sourceClass);// Process superclass, if anyif (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn null;}
额又是常长的方法,不用怕,我们看下代码,发现有如下几处注释有点熟悉
// Process any @PropertySource annotations// Process any @ComponentScan annotations// Process any @Import annotations// Process any @ImportResource annotations// Process individual @Bean methods/ Process default methods on interfaces
我们一眼就看到了我们的目的 @ComponentScan 那其它我们就不看先。
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediatelySet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}
开始先获取了componentScans注解信息,我们知道为
basePackages=[com.suibibk.spring]
我们直接看代码
// The config class is annotated with @ComponentScan -> perform the scan immediatelySet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
这里解析该componentScan返回BeanDefinitionHolders,可以大胆的推测这个方法里面一定去扫描了com.suibibk.spring路径下面的所有类和子类,如果有@component注解则会解析为BeanDefinition注册到放到了DefaultListableBeanFactory中的beanDefinitionMap中,key为bean的名称,值为beanDefinition放的应该是这些类的相关类定义,其实我有点奇怪为啥这里还要返回,解析完就直接放到beanDefinitionMap中了啊。然后我看到了下面。
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}
原来是怕解析出来的类有些也是配置类。
好了我们继续跟进去上面的parse方法去
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :BeanUtils.instantiateClass(generatorClass));ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");if (scopedProxyMode != ScopedProxyMode.DEFAULT) {scanner.setScopedProxyMode(scopedProxyMode);}else {Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));}scanner.setResourcePattern(componentScan.getString("resourcePattern"));for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {for (TypeFilter typeFilter : typeFiltersFor(filter)) {scanner.addIncludeFilter(typeFilter);}}for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {for (TypeFilter typeFilter : typeFiltersFor(filter)) {scanner.addExcludeFilter(typeFilter);}}boolean lazyInit = componentScan.getBoolean("lazyInit");if (lazyInit) {scanner.getBeanDefinitionDefaults().setLazyInit(true);}Set<String> basePackages = new LinkedHashSet<>();String[] basePackagesArray = componentScan.getStringArray("basePackages");for (String pkg : basePackagesArray) {String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);Collections.addAll(basePackages, tokenized);}for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {basePackages.add(ClassUtils.getPackageName(clazz));}if (basePackages.isEmpty()) {basePackages.add(ClassUtils.getPackageName(declaringClass));}scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {@Overrideprotected boolean matchClassName(String className) {return declaringClass.equals(className);}});return scanner.doScan(StringUtils.toStringArray(basePackages));}
其实这个前面都不用看,扫描一样就发现了最重要的代码
return scanner.doScan(StringUtils.toStringArray(basePackages));
话说,spring习惯把最终要执行的代码方法名称以do开头。
/*** Perform a scan within the specified base packages,* returning the registered bean definitions.* <p>This method does <i>not</i> 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<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {Set<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);registerBeanDefinition(definitionHolder, this.registry);}}}
我们看这一行
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
这里直接就根据包路径返回了所有的BeanDefinition,所以这里绝bi是一行关键代码,后面就直接遍历candidates注册到DefaultListableBeanFactory中了,这个我们在this()方法里面注册一些后置处理器的时候看过,这里就不多说。
/*** 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<BeanDefinition> findCandidateComponents(String basePackage) {if (this.componentsIndex != null && indexSupportsIncludeFilters()) {return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);}else {return scanCandidateComponents(basePackage);}}
扫描类路径,寻找候选组件。
直接看
return scanCandidateComponents(basePackage);
不要问我为啥不看
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
额,按直觉来说我就不会选择它,看源码不要想着一下就全部弄明白,要靠直觉和大胆的推测以及略过看不懂的先再辅助于调试就可以了。
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();try {//拼接路径,这里是:classpath*:com/suibibk/spring/**/*.classString packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;//根据路径获得资源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);//判断是否是候选Component,也就是加了@Component注解的类if (isCandidateComponent(metadataReader)) {//是的化这里就创建BeanDefinitionScannedGenericBeanDefinition 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;}
大概过程是
1、拼接路径获得包扫描真实的路径
2、获得资源集合
3、遍历资源获得可读的元标签数据
4、判断是否是候选的组件
5、如果是候选的组件则生成BeanDefinition加入集合中
6、返回候选集合。
到这里终于把配置类解析完了。接下来就是上面说的,循环遍历候选集合注册到DefaultListableBeanFactory的beanDefinitionMap中。
registerBeanDefinition(definitionHolder, this.registry);
关键点总结:
1、register(componentClasses);方法把配置类注册到DefaultListableBeanFactory的beanDefinitionMap中。
2、refresh();中的invokeBeanFactoryPostProcessors(beanFactory);解析配置类,把@ComponentScan(basePackages = “com.suibibk.spring”)路径下的所有加了@Component注解的类注册到DefaultListableBeanFactory的beanDefinitionMap中。
接下来就应该是bean初始化了,毕竟该有的东西都已经在DefaultListableBeanFactory的beanDefinitionMap中了。
