|  
 有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本2.7.0  前言紧接上文,下一步是创建和准备上下文 			
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
 核心类ServletWebServerApplicationContextServletWebServerApplicationContext从名字上看,它是一个基于Servlet Web 服务的应用上下文,它的类图如下:
  它是
 Spring Boot提供的基于Servlet 开发时使用的一个IOC容器,从它的类继承可以看出,它依赖于Spring MVC,而且还提供了两个子类,从名字就知道一个是基于注解,一个是基于XML注册的容器。
 
 AnnotatedBeanDefinitionReader ClassPathBeanDefinitionScannerAnnotatedBeanDefinitionReader从名字上理解,是一个注解方式的BeanDefinition读取器,学过Spring 的都知道首先会加载BeanDefinition,然后根据BeanDefinition生成Bean 对象,这个类的主要作用就是就是加载BeanDefinition了。
 ClassPathBeanDefinitionScanner的作用也是加载BeanDefinition,不过从它的名字中,我们知道是一个扫描指定类路径中的BeanDefinition扫描器。
 上面这两个类作用都是Bean 定义的加载。 1. 创建应用上下文createApplicationContext方法直接调用工厂类创建对象:
     protected ConfigurableApplicationContext createApplicationContext() {
        return this.applicationContextFactory.create(this.webApplicationType);
    }
 这个工厂类是SpringApplication类的成员属性,是ApplicationContextFactory的内部类DEFAULT: this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
 所以直接进入了ApplicationContextFactory 的内部匿名实现类中: 	ApplicationContextFactory DEFAULT = (webApplicationType) -> {
		try {
			
			
			for (ApplicationContextFactory candidate : SpringFactoriesLoader
					.loadFactories(ApplicationContextFactory.class, ApplicationContextFactory.class.getClassLoader())) {
				
				ConfigurableApplicationContext context = candidate.create(webApplicationType);
				if (context != null) {
					return context;
				}
			}
			return AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext()
					: new AnnotationConfigApplicationContext();
		}
		catch (Exception ex) {
			throw new IllegalStateException("Unable create a default ApplicationContext instance, "
					+ "you may need a custom ApplicationContextFactory", ex);
		}
	};
 进入到AnnotationConfigServletWebServerApplicationContext内部类创建工厂时,因为类型为SERVLET ,所以会直接new一个无参构造方法创建应用上下文对象:     public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
            return webApplicationType != WebApplicationType.SERVLET ? null : new AnnotationConfigServletWebServerApplicationContext();
   }
 学过JAVA 的都知道,子类的构造函数会隐式调用父类的无参构造函数,所以我们先看下AnnotationConfigServletWebServerApplicationContext的父类构造器中,都做了些什么。 首先是AbstractApplicationContext     public AbstractApplicationContext() {
        this.logger = LogFactory.getLog(this.getClass());
        
        
        this.id = ObjectUtils.identityToString(this);
        
        this.displayName = ObjectUtils.identityToString(this);
        
        this.beanFactoryPostProcessors = new ArrayList();
        
        this.active = new AtomicBoolean();
        
        this.closed = new AtomicBoolean();
        
        this.startupShutdownMonitor = new Object();
        
        this.applicationStartup = ApplicationStartup.DEFAULT;
        
        this.applicationListeners = new LinkedHashSet();
        
        this.resourcePatternResolver = this.getResourcePatternResolver();
    }
 接着是GenericApplicationContext:     public GenericApplicationContext() {
    	
        this.customClassLoader = false;
        
        this.refreshed = new AtomicBoolean();
        
        this.beanFactory = new DefaultListableBeanFactory();
    }
 接着到本类中:     public AnnotationConfigServletWebServerApplicationContext() {
    	
        this.annotatedClasses = new LinkedHashSet();
        
        this.reader = new AnnotatedBeanDefinitionReader(this);
        
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
 最后,通过构造函数,应用上下文就创建成功了,但是大部分属性都是NULL ,这个创建创建阶段只是完成了初始化对象的创建操作。
  2. 准备上下文接下来进入到prepareContext准备上下文方法中:     private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    	
        context.setEnvironment(environment);
        
        this.postProcessApplicationContext(context);
        
        this.applyInitializers(context);
        
        listeners.contextPrepared(context);
        
        bootstrapContext.close(context);
        
        
        
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }
		
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
        	
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
		
        if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
        
            ((AbstractAutowireCapableBeanFactory)beanFactory).setAllowCircularReferences(this.allowCircularReferences);
            if (beanFactory instanceof DefaultListableBeanFactory) {
                
                ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
            }
        }
		
        if (this.lazyInitialization) {
        	
        	
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        
        context.addBeanFactoryPostProcessor(new SpringApplication.PropertySourceOrderingBeanFactoryPostProcessor(context));
        
        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        
        this.load(context, sources.toArray(new Object[0]));
        
        listeners.contextLoaded(context);
    }
 在setEnvironment方法中会将环境对象设置给上下文及读取器和扫描器:     public void setEnvironment(ConfigurableEnvironment environment) {
        super.setEnvironment(environment);
        this.reader.setEnvironment(environment);
        this.scanner.setEnvironment(environment);
    }
 postProcessApplicationContext方法只有最后一行代码实际执行了,设置ConversionService给上下文中的Bean 工厂:
     protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    	
        if (this.beanNameGenerator != null) {
            context.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", this.beanNameGenerator);
        }
		
        if (this.resourceLoader != null) {
            if (context instanceof GenericApplicationContext) {
                ((GenericApplicationContext)context).setResourceLoader(this.resourceLoader);
            }
            if (context instanceof DefaultResourceLoader) {
                ((DefaultResourceLoader)context).setClassLoader(this.resourceLoader.getClassLoader());
            }
        }
        if (this.addConversionService) {
            context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
        }
    }
 在applyInitializers方法中会调用之前SPI 机制加载的ApplicationContextInitializer的所有实例的初始化方法, protected void applyInitializers(ConfigurableApplicationContext context) {
        Iterator var2 = this.getInitializers().iterator();
        
        while(var2.hasNext()) {
            ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
            
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            
            initializer.initialize(context);
        }
    }
 在之前我们了解过,一共有7 中应用初始化器,最先进入的是DelegatingApplicationContextInitializer,之前我们说过,它是一个委托的初始化器,会加载context.initializer.classes配置的初始化器,然后进行调用,代码如下:
  第二个进入的是
 SharedMetadataReaderFactoryContextInitializer,它的主要作用是创建了一个Bean 工厂后置处理器并设置到上下文中。     public void initialize(ConfigurableApplicationContext applicationContext) {
    	
        BeanFactoryPostProcessor postProcessor = new SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor(applicationContext);
        applicationContext.addBeanFactoryPostProcessor(postProcessor);
    }
 第三个是ContextIdApplicationContextInitializer,作用为创建一个ContextId对象,并将其注册到Bean 工厂中,     public void initialize(ConfigurableApplicationContext applicationContext) {
    	
        ContextIdApplicationContextInitializer.ContextId contextId = this.getContextId(applicationContext);
        applicationContext.setId(contextId.getId());
     	
     	applicationContext.getBeanFactory().registerSingleton(ContextIdApplicationContextInitializer.ContextId.class.getName(), contextId);
    }
 第四个是ConfigurationWarningsApplicationContextInitializer,主要是添加了警告后置处理器,检查注解扫描的包是否有问题,如果有,则返回警告:    public void initialize(ConfigurableApplicationContext context) {
   		
        context.addBeanFactoryPostProcessor(new ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor(this.getChecks()));
    }
 第五个是RSocketPortInfoApplicationContextInitializer,主要是添加了一个RSocketServerInitializedEvent事件的监听器到上下文中,可以通过该事件将RSocketServer服务器实际监听的端口设置到环境属性中。     public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.addApplicationListener(new RSocketPortInfoApplicationContextInitializer.Listener(applicationContext));
    }
 第六个是ServerPortInfoApplicationContextInitializer,它本身也是一个监听器,监听的事件为WebServerInitializedEvent,可以将端口设置到环境中,然后方便通过@Value或environment获取本地端口号。     public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.addApplicationListener(this);
    }
 第七个是ConditionEvaluationReportLoggingListener,也是加了一个监听器,可以打印上下文容器成功刷新或失败的日志报告。     public void initialize(ConfigurableApplicationContext applicationContext) {
    	
        this.applicationContext = applicationContext;
        
        applicationContext.addApplicationListener(new ConditionEvaluationReportLoggingListener.ConditionEvaluationReportListener());
        
        if (applicationContext instanceof GenericApplicationContext) {
            this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
        }
    }
 至此所有初始化器的任务完成了,我们的上下文又多了不少东西,有监听器、ID、后置处理器等。
  接着进入到listeners.contextPrepared(context)方法,调用SpringApplicationRunListeners监听器,开始进入下一步骤阶段。 和之前应用启动时一样,也响应的创建一个步骤,名称为spring.boot.application.context-prepared(上下文准备完成),然后调用那些监听器中ApplicationPreparedEvent事件的响应方法,这里就懒得看了,主要有注册springBootLoggingSystem、springBootLoggerGroups、打印日志的一些工作。 接着prepareContext方法又添加了一些后置处理器和加载了一些Bean ,最后进入load方法,将启动类BeanDefinition注册。     protected void load(ApplicationContext context, Object[] sources) {
    	
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
		
        BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
        
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
		
        loader.load();
    }
    private void load(Class<?> source) {
    	
    	
        if (this.isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            GroovyBeanDefinitionSource loader = (GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
            ((GroovyBeanDefinitionReader)this.groovyReader).beans(loader.getBeans());
        }
		
        if (this.isEligible(source)) {
        	
        	
            this.annotatedReader.register(new Class[]{source});
        }
    }
 此时可以看到当前Bean 工厂中,有6个 BeanDefinition。
  最后调用listeners.contextLoaded进行监听器的处理,这里发布的是ApplicationPreparedEvent事件,可以看到有5个监听器符合,然后就是和之前一样,调用每个监听器的监听方法处理事件,这个阶段好像没做很重要的处理,就不解释了。
  处理完成后,
 prepareContext 这个阶段就完成了,经过创建和准备工作,我们的上下文已经又多了不少东西,接下来就进入刷新方法了。
  |