Preliminary Study on Spring 5 Source Parsing 3-refresh Method

Posted by n8r0x on Sat, 05 Oct 2019 05:11:06 +0200

Next, after analyzing register (annotated classes) last time, let's look at refresh(); method.

// New Annotation Config Application Context (AppConfig. class); source code
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    //Call the default parameterless constructor, which has a lot of initialization logic
    this();

    //Register the incoming Class, either with @Configuration annotation or without @Configuration annotation
    //How to register? Delegated to the org. spring framework. context. annotation. AnnotatedBeanDefinitionReader. register method for registration
    // Input Class generates BeanDefinition, and then registers to BeanDefinition Registry
    register(annotatedClasses);

    //Refresh Container Context
    refresh();
}

refresh method

Click on refresh(); Method, which calls a super many methods, let's look at each one.

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        //Prepare the context, set its start date and activity flag, and initialize the property source
        prepareRefresh();
    
        // Tell the subclass to refresh the internal bean factory.
        //Call the subclass refreshBeanFactory() method
        //Get the BeanFactory instance DefaultListableBeanFactory, DefaultListableBeanFactory implements the Configurable ListableBeanFactory interface
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
        // Prepare the bean factory for use in this context.
        //Configure the bean Factory context
        //1. Add Application Context Aware Processor and Application Listener Detector
        //2. Ignoring some types of automatic assembly
        //3. Register special dependency types and use corresponding autowired values
        //4. Register default environment beans
        //5. Setting up environment beans
        prepareBeanFactory(beanFactory);
    
        try {
            // Allows post-processing of the bean factory in context subclasses.
            //A method left to subclasses to extend
            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();
        }
    }
}

prepareRefresh();

prepareRefresh(); Prepare the context, set its start date and activity flag, and initialize the property source.

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.
    //This is an empty method. Annotationconfiguapplicationcontext does not Override the method.
    initPropertySources();

    // Validate that all properties marked as required are resolvable:
    // see ConfigurablePropertyResolver#setRequiredProperties
    getEnvironment().validateRequiredProperties();

    // Store pre-refresh ApplicationListeners...
    if (this.earlyApplicationListeners == null) {
        //By default, earlyApplication Listeners are 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<>();
}

obtainFreshBeanFactory();

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

refreshBeanFactory(); is an abstract method with two specific implementations:

AnnotationConfigApplicationContext inherits GenericApplicationContext, so it is obvious that the method executed here should be in the GenericApplicationContext class. The refreshBeanFactory() source code for Generic Application Context is as follows:

//Generic Application Context # refreshBeanFactory source code
@Override
protected 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());
}

obtainFreshBeanFactory(); method finally calls getBeanFactory(); method, and returns the Configurable Listable BeanFactory object.

getBeanFactory(); as the name implies, is to get BeanFactory, Spring uses DefaultListableBeanFactory, which also implements the Configurable ListableBeanFactory interface.

prepareBeanFactory(beanFactory);

prepareBeanFactory(beanFactory); Source code is relatively simple:

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.
    //Add BeanPostProcessor instance ApplicationContextAware Processor
    //The main function of Application Context Aware Processor is to support Aware interface. If the corresponding Aware interface is implemented, the corresponding resources are injected.
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

    //By default, only the BeanFactoryAware interface is ignored, and now the following types of automatic assembly are ignored
    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.

    //Register automatic assembly rules. If you find a specific type, use the specified value injection.
    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.
    //Register default environment beans.
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        // Environment
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        // System Properties
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        // System Environment
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

ApplicationContextAwareProcessor

prepareBeanFactory(beanFactory); The method adds an ApplicationContextAware Processor object to the beanFactory: beanFactory. addBeanPostProcessor (new ApplicationContextAware Processor (this);.

The ApplicationContextAwareProcessor class implements the BeanPostProcessor interface, which is mainly the Override postProcessBeforeInitialization method. Its function is mainly to support the Aware series interface. When it finds that the Bean implements the Aware series interface, it calls its corresponding methods. For which Aware interfaces, please see the source code:

//Application Context Aware Processor#postProcessBeforeInitialization source code
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    AccessControlContext acc = null;

    if (System.getSecurityManager() != null &&
            (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                    bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                    bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
        acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    }

    if (acc != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareInterfaces(bean);
            return null;
        }, acc);
    } else {
        invokeAwareInterfaces(bean);
    }

    return bean;
}

private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
        }
        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }
        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
        }
        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
        }
        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
        }
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }
}

Now that the program runs here, take a look at the data in the Spring container.

  • 6 BeanDefinition objects
  • Three Single Bean s
  • Two BeanPost Processors

postProcessBeanFactory(beanFactory);

This is an empty method left to subclasses to expand, and the method in the AnnotationConfigApplicationContext class does nothing.

To be continued...

Source Learning Notes: https://github.com/shenjianen...

Welcome to pay attention to the public number:

Topics: Java Spring github