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


    一、前言

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

     简介

    二、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什么时候执行的呢?
    • 这个比较麻烦,我们后面单开一节再详细的去看。

     丰极

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

  • 相关阅读:
    依次逐个亮灯并且每次只能亮一个灯的跑马灯程序
    逐个点亮LED灯,再逐个熄灭LED灯的跑马灯程序---基于74HC595移位锁存器,程序框架用switch语句
    把74HC595驱动程序翻译成类似单片机IO口直接驱动的方式
    两片联级74HC595驱动16个LED灯的基本驱动程序
    树莓派
    Linux I2C驱动
    转:使用 /proc 文件系统来访问 Linux 内核的内容
    转: 使用 /sys 文件系统访问 Linux 内核
    树梅派 -- 通过/sys读写ADC芯片 pcf8591
    树莓派 -- oled 续(2) python
  • 原文地址:https://www.cnblogs.com/zhangbin1989/p/14278018.html
Copyright © 2020-2023  润新知