4

springboot源码解析-管中窥豹系列之aware(六)

 3 years ago
source link: http://www.cnblogs.com/zhangbin1989/p/14278018.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、前言

  • Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去。
  • 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot源码管中窥豹系列。

JZR3YrV.png!mobile

二、ApplicationContextAware

  • 假设我们想使用某个bean, 如果是在@Component类下面,直接用@Autowired引用就行了
  • 假设我们想在某个静态方法里面用,就不能用上面的方法了
  • 你可能想用new Bean()的方式,new一个,但是这个bean里面的@Autowired引用用不了
  • 如果有一个静态的全局ApplicationContext就好了,用spring的能力获取bean: ApplicationContext.getBean(clazz)
  • ApplicationContextAware就是这个用处
public interface ApplicationContextAware extends Aware {

	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

public interface Aware {

}

我们写一个实现类:

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);
    }

}
  • 通过setApplicationContext,把applicationContext赋值到本地静态变量
  • 通过ApplicationContext的getBean就可以在静态方法中使用任何bean的能力了

三、源码分析

我们进入SpringApplication的run方法:

public ConfigurableApplicationContext run(String... args) {

    ...

    try {
        
        ...

        refreshContext(context);
        
        ...
    }
    catch (Throwable ex) {
       
       ...

    }

    ...

    return context;
}

我们进入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();
        }
    }
}

这个refresh是spring的核心方法,以后会多次用到,内容太多,我们这次只关注一个方法:

  • prepareBeanFactory(beanFactory);
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        ...

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        ...
    }
}

我们先看prepareBeanFactory(beanFactory):

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

    ...

    // Configure the bean factory with context callbacks.
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

    ...
    
}

我们看一下这个addBeanPostProcessor方法

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);
}
  • 先remove,再add
  • beanPostProcessors是一个线程安全的list: CopyOnWriteArrayList
  • 我们往下看看new ApplicationContextAwareProcessor(this),注意:this是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);
		}
	}

}
  • 构造方法,把applicationContext设到本地变量上
  • 实现接口的方法:postProcessBeforeInitialization,回调的时候会用,主要是校验权限
  • 最下面的invokeAwareInterfaces是个私有的核心回调方法,根据不同类型,有不同回调

我们看到除了ApplicationContextAware,还有其它的aware, 总共6个

  • EnvironmentAware:环境变量
  • EmbeddedValueResolverAware:值解析器
  • ResourceLoaderAware:资源加载器
  • ApplicationEventPublisherAware:事件发布器
  • MessageSourceAware:信息处理器
  • ApplicationContextAware:spring容器

比如我们想用全局的环境变量,就有EnvironmentAware,想用spring的事件就用ApplicationEventPublisherAware,等等

  • 来源找到了,ApplicationContextAwareProcessor什么时候执行的呢?
  • 这个比较麻烦,我们后面单开一节再详细的去看。

ZBbERjA.jpg!mobile

欢迎关注微信公众号:丰极,更多技术学习分享。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK