本文主要是介绍揭密springboot自动装配(3)--ioc及调用selectImposts,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
接着上一章的提问,何处调用了这个selectImposts方法?
我们从这个启动类的SpringApplication.run方法跟进去
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);prepareContext(context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}
这段代码里面我们只关注refreshContext(context);即可
refresh继续走
public 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();}}}
从注释上看 invokeBeanFactoryPostProcessors(beanFactory);是一个上下文中调用注册为bean的工厂处理器
这章我们关注点就在这里
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()));}}
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors这里面调用了
BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry
BeanDefinitionRegistryPostProcessor是个接口,我们关注的主要实现是ConfigurationClassPostProcessor
@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(BeanDefinitionRegistry registry)里走,这里面ConfigurationClassParser.parse()和loadBeanDefinitions,从名字我们就可以猜到是解析和加载bean定义
我们先进到parse方法进去看看究竟
接着走ConfigurationClassParser.processConfigurationClass->ConfigurationClassParser.doProcessConfigurationClass
doProcessConfigurationClass方法里面有着怎么一段process any @import annotations
从这里我们可以看到熟悉的@import,明显这里专门处理import相关,我进去瞧瞧
进去之后我们终于发现,咦,就在这里调用了我们上一章实现的selectImports
debug进来可以看到我们定义的UserA和UserB
这段processImports是个递归操作,拿到我们定义的UserA和UserB之后接着继续递归传进来
递归进来之后再调用ConfigurationClassParser.processConfigurationClass
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);}
然后将configClass放入到configurationClasses这个map里面去:this.configurationClasses.put(configClass, configClass);
好了我们接着回到ConfigurationClassPostProcessor.processConfigBeanDefinitions
前面parse解析完的类放在了configurationClasses里面,现在我们parser.getConfigurationClasses获取出来接着进行bean定义,也就是loadBeanDefinitions
接着循环所有configclass调用loadBeanDefinitionsForConfigurationClass
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {if (trackedConditionEvaluator.shouldSkip(configClass)) {String beanName = configClass.getBeanName();if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {this.registry.removeBeanDefinition(beanName);}this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());return;}if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);}for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);}loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}
进入这里调用registerBeanDefinitionForImportedConfigurationClass进去bean的注册
接着我们继续跟进去
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {AnnotationMetadata metadata = configClass.getMetadata();AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);configBeanDef.setScope(scopeMetadata.getScopeName());String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());configClass.setBeanName(configBeanName);if (logger.isTraceEnabled()) {logger.trace("Registered bean definition for imported class '" + configBeanName + "'");}}
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
从这里可以发现其实就是创建了BeanDefinitionHolder,然后将BeanDefinition传入DefaultListableBeanFactory.registerBeanDefinition,我们进到registerBeanDefinition这个方法里面会发现
这里将BeanDefinition放入beanDefinitionMap里面,这样我们就完成了bean的注册工作啦
到这里,我们应该还是有个疑问就是:这个放入beanDefinitionMap的类信息,什么时候进行实现new UserA()操作呀?
下一章我们就这个问题再深入探讨
这篇关于揭密springboot自动装配(3)--ioc及调用selectImposts的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!