One, foreword

  • Springboot source code parsing is a big project, line by line to study the code, can be boring, and not easy to stick to.
  • We do not pursue big and complete, but try to study a small knowledge point every time, and eventually together, this is our Springboot source tube leopard series.

Second, the ApplicationContextAware

  • Let’s say we want to use a bean. If it’s under the @Component class, we’ll just use the @AutoWired reference
  • Let’s say we want to use it in some static method, we can’t use the above method
  • You might want to use a new Bean(), but the @autoWired reference inside the Bean doesn’t work
  • If you have a static global ApplicationContext, spring on the ability to gain bean: ApplicationContext. GetBean (clazz)
  • ApplicationContextAware is used for this purpose
public interface ApplicationContextAware extends Aware {

	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

public interface Aware {

}

Copy the code

Let’s write an implementation class:

import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtil.applicationContext = applicationContext; } private static ApplicationContext getApplicationContext() { return applicationContext; } public static <T> T getBean(Class<T> clazz){ return getApplicationContext().getBean(clazz); }}Copy the code
  • Using setApplicationContext, you assign applicationContext to a local static variable
  • You can use any bean’s capabilities in static methods through the getBean of the ApplicationContext

Third, source code analysis

We go to the run method of the SpringApplication:

public ConfigurableApplicationContext run(String... args) { ... try { ... refreshContext(context); . } catch (Throwable ex) { ... }... return context; }Copy the code

We go inside refreshContext(context) :

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); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); }}}Copy the code

This refresh method is the core method of Spring and will be used many times in the future, so we’ll focus on just one method this time:

  • prepareBeanFactory(beanFactory);
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); . }}Copy the code

Let’s look at prepareBeanFactory(beanFactory) :

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { ... // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); . }Copy the code

Let’s take a look at this addBeanPostProcessor method


private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    // Remove from old position, if any
    this.beanPostProcessors.remove(beanPostProcessor);
    // Track whether it is instantiation/destruction aware
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
        this.hasInstantiationAwareBeanPostProcessors = true;
    }
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
        this.hasDestructionAwareBeanPostProcessors = true;
    }
    // Add to end of list
    this.beanPostProcessors.add(beanPostProcessor);
}
Copy the code
  • Remove, and then add
  • BeanPostProcessors is a thread-safe list: CopyOnWriteArrayList
  • We see new ApplicationContextAwareProcessor down (this), note: this is the ApplicationContext
class ApplicationContextAwareProcessor implements BeanPostProcessor { private final ConfigurableApplicationContext applicationContext; private final StringValueResolver embeddedValueResolver; /** * Create a new ApplicationContextAwareProcessor for the given context. */ public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) { this.applicationContext = applicationContext; this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory()); } @Override @Nullable public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (! (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){ return bean; } AccessControlContext acc = null; if (System.getSecurityManager() ! = null) { 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 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); }}}Copy the code
  • Constructor that sets applicationContext to a local variable
  • The method of implementing an interface: postProcessBeforeInitialization, will use the callback, mainly is the check permissions
  • The invokeAwareInterfaces at the bottom is a private core callback method with different callbacks depending on the type

We see that in addition to ApplicationContextAware, there are six other aware

  • EnvironmentAware: Environmental variables
  • The parser EmbeddedValueResolverAware: value
  • ResourceLoaderAware: Resource loader
  • ApplicationEventPublisherAware: event publishing
  • MessageSourceAware: Information processor
  • ApplicationContextAware: Spring container

We want to use the global environment variables, for example, have EnvironmentAware, want to use spring’s event with ApplicationEventPublisherAware, and so on

  • Source is found, ApplicationContextAwareProcessor when executed?
  • This is more troublesome, we will open a section and then look in detail.

Welcome to follow the wechat public number: Fengji, more technical learning and sharing.