preface

In this section, let’s take a look at the refresh method, the core method of Spring startup.

Refresh method, Spring Bean configuration read loading entry, is also the Spring framework startup process.

The refresh method

An overview of refresh methods

Springapplication.run (String… The args) look.

// SpringApplication # run(String... args) # 311-313
public ConfigurableApplicationContext run(String... args) {
      / /.....................
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);
      / /.....................
        return context;
    }
Copy the code

We go into the body of the refreshContext(context) method:

// SpringApplication # refreshContext(ConfigurableApplicationContext context) # 390
private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.}}}Copy the code

Obviously, the core method still calls refresh(context) :

    // SpringApplication # refresh(ApplicationContext applicationContext) # 742
protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext) applicationContext).refresh();
    }
Copy the code

Continue to enter (AbstractApplicationContext applicationContext). The refresh () :

// AbstractApplicationContext # refresh() # 515
public void refresh(a) throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
      // Prepare the context for refreshing the container
            prepareRefresh();
            // Tell the subclass to refresh the internal bean factory.
      // Tell the subclass to refresh the internal bean factory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // Prepare the bean factory for use in this context.
      // The bean factory to be used in this context.
            prepareBeanFactory(beanFactory);
            try {
              // Allows post-processing of the bean factory in context subclasses.
        // Allow post-processing of bean factories in context subclasses
                postProcessBeanFactory(beanFactory);
                // Invoke factory processors registered as beans in the context.
         // Call the factory handler registered as a bean in the context.
                invokeBeanFactoryPostProcessors(beanFactory);
                // Register bean processors that intercept bean creation.
         // Register the Bean handler created by the intercepting Bean.
                registerBeanPostProcessors(beanFactory);
                // Initialize message source for this context.
        // Initialize the message source for this context.
                initMessageSource();
                // Initialize event multicaster for this context.
        // Initializes the event broadcaster for the context
                initApplicationEventMulticaster();
                // Initialize other special beans in specific context subclasses.
        // Initialize other special beans in specific context subclasses.
                onRefresh();
                // Check for listener beans and register them.
        // Check the listener and register it.
                registerListeners();
                // Instantiate all remaining (non-lazy-init) singletons.
         // Instantiate all remaining (non-delayed initialization) singletons.
                finishBeanFactoryInitialization(beanFactory);
                // Last step: publish corresponding event.
        // Publish the corresponding event.
                finishRefresh();
            }
      / /.....................
    }
Copy the code

prepareRefresh

Method note: Prepare this context for refresh, set its start date and activity flag, and perform any initialization of the property source.

protected void prepareRefresh(a) {
        // Set the start date and the active flag
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
    / /.....................
        // Initialize any placeholder property sources in the context environment.
         // Initialize property Settings
        initPropertySources();
 
        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
      // Verify the required attributes
        getEnvironment().validateRequiredProperties();
 
        // Store pre-refresh ApplicationListeners...
    // Save the listener before the refresh
        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<>();
    }
Copy the code

obtainFreshBeanFactory

// AbstractApplicationContext # obtainFreshBeanFactory() # 635
protected ConfigurableListableBeanFactory obtainFreshBeanFactory(a) {
        refreshBeanFactory();
        return getBeanFactory();
    }
Copy the code

This method is relatively simple. It does two things:

  • Set the serialization ID of the beanFactory
  • Get beanFacotory

prepareBeanFactory

This method sets the properties of the beanFacotory obtained from obtainFreshBeanFactory().

Method comments: Configure the factory’s standard context characteristics, such as ClassLoader and post-processor for the context

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
    // Tell the internal bean factory to use the context's classloader, etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
 
        // Configure the bean factory with context callbacks.
    // Use context callbacks to configure the Bean factory.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // Configure ignored dependencies
        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.
    // The BeanFactory interface is not registered as a resolvable type in a normal factory.
        // MessageSource registered (and found for autowiring) as a bean.
    // MessageSource is registered as a Bean (and discovered for autoliring).
        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.
    // Register an early post-processor to detect internal beans as ApplicationListeners.
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
 
        // Detect a LoadTimeWeaver and prepare for weaving, if found.
    // Check the LoadTimeWeaver and prepare to weave (if found).
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
      // Set up a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
 
        // Register default environment beans.
    // Register the default environment Bean.
        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());
        }
    }
Copy the code

This method does several things:

  • Set some properties of the beanFactory
  • Add a post processor
  • Set the ignored autolight interface
  • Register some components

postProcessBeanFactory(beanFactory)

Here is an empty implementation, left to subclasses to override. Further Settings can be made after the beanFactory is created.

For servlets, this is to set some scope, such as request, session, and so on.

invokeBeanFactoryPostProcessors(beanFactory)

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(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}Copy the code

The main logic in invokeBeanFactoryPostProcessors (the beanFactory, getBeanFactoryPostProcessors ()) :

This method body is too long, so I won’t post it. Two main things were done:

  • Call BeanDefinitionRegistryPostProcessor implementation to the container to add bean definition.

    We actually did this in the previous section, and here is the Bean we added.

    @Componentpublic class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {    @Override    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();        rootBeanDefinition.setBeanClass(MyTwoBean.class);        beanDefinitionRegistry.registerBeanDefinition("myTwoBean",rootBeanDefinition);    }    @Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}}Copy the code
  • Call the BeanFactoryPostProcessor implementation to add properties to the definition of adding beans to the container.

registerBeanPostProcessors(beanFactory)

This method and invokeBeanFactoryPostProcessors (the beanFactory) is similar.

Find the implementation of BeanPostPocessor, sort it and register it in the container.

initMessageSource()

Mainly internationalized, multilingual configuration.

That’s not the point. Skip it.

initApplicationEventMulticaster()

Initializes the event broadcaster. We’ve looked at listeners before. It’s similar here.

// Use a listener if there is one; If not, create a new one. protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); }}
Copy the code

onRefresh()

Subclass implementation. Servlet is used to create a Web container.

// ServletWebServerApplicationContext # onRefresh() # 150protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); }}
Copy the code

We know that super.onRefresh() is an empty implementation, so look directly at createWebServer() :

// This method is the method to create the container. We'll leave it at that. private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext ! = null) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }
Copy the code

registerListeners()

    protected void registerListeners(a) {        // Register statically specified listeners. // Register statically specified listeners first. for (ApplicationListener
       listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } / / the container listenerBean registered String [] listenerBeanNames = getBeanNamesForType (ApplicationListener. Class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... // When the Bean is not loaded, the event cannot be published, so temporarily stored in earlyApplicationEvents // until then, the saved event will be published. Set
      
        earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess ! = null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); }}}
      
Copy the code

finishBeanFactoryInitialization(beanFactory)

Instantiate all instances of BeanFactory that have been registered but have not been instantiated.

This is the important Bean instantiation process. So we’ll do a separate section on that later.

So, for the time being, not to explore the source code.

finishRefresh()

protected void finishRefresh(a) {    // Clear context-level resource caches (such as ASM metadata from scanning). // Clear resourcecaches (); // Initialize lifecycle Processor for this context. // initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); PublishEvent (new ContextRefreshedEvent(this)); publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
Copy the code

resetCommonCaches()

This method is called in finally {} to do some cache clearing.

    protected void resetCommonCaches(a) {        ReflectionUtils.clearCache();        AnnotationUtils.clearCache();        ResolvableType.clearCache();        CachedIntrospectionResults.clearClassLoader(getClassLoader());    }
Copy the code

conclusion

At this point, we have gone through the refresh method.

Again, this section focuses on the overall process of Refresh. For some details, leave for later slowly study, one bite and eat not a big fat man.