Spring读源码系列06----容器扩展功能--上

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列06----容器扩展功能--上相关的知识,希望对你有一定的参考价值。

Spring读源码系列06----容器扩展功能---上


ApplicationContext


  • 使用BeanFactory方式加载XML
        ClassPathResource classPathResource = new ClassPathResource("bean.xml");
        BeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);
  • 使用ApplicationContext方式加载XML
        ApplicationContext bc=new ClassPathXmlApplicationContext("bean.xml");


ClassPathXmlApplicationContext构造函数

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException 
        this(new String[]configLocation, true, (ApplicationContext)null);
    
     |
     |
    \\|/
     |
        public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException 
        super(parent);
        //设置配置文件路径
        this.setConfigLocations(configLocations);
        if (refresh) 
        //刷新容器
            this.refresh();
        

      



AbstractRefreshableConfigApplicationContext#setConfigLocations—设置配置文件路径

    public void setConfigLocations(@Nullable String... locations) 
        if (locations != null) 
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];

            for(int i = 0; i < locations.length; ++i) 
            //解析给定配置文件路径
                this.configLocations[i] = this.resolvePath(locations[i]).trim();
            
         else 
            this.configLocations = null;
        

    

    protected String resolvePath(String path) 
    //ConfigurablePropertyResolver负责解析path路径
        return this.getEnvironment().resolveRequiredPlaceholders(path);
    

AbstractApplicationContext#refresh—刷新容器

    public void refresh() throws BeansException, IllegalStateException 
    //startupShutdownMonitor可以确保当前应用在刷新过程中是同步的
        synchronized(this.startupShutdownMonitor) 
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            //准备此上下文以进行刷新、设置其启动日期和活动标志以及执行任何属性源的初始化。
            this.prepareRefresh();
            //初始化BeanFactory,并进行xml文件读取---原beanFactory的初始化步骤在这一步完成
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //配置工厂的标准上下文特征,例如上下文的 ClassLoader 和后处理器。
            this.prepareBeanFactory(beanFactory);

            try 
            //子类覆盖父类方法做额外处理:
            
            //在标准初始化之后修改应用程序上下文的内部 bean 工厂。
            //所有 bean 定义都将被加载,但还没有 bean 被实例化。
            //这允许在某些 ApplicationContext 实现中注册特殊的 BeanPostProcessors 等。
                this.postProcessBeanFactory(beanFactory);  
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                //触发bean工厂后置处理器
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //注册拦截bean创建的bean处理器,这里只是注册,真正调用是在getBean的时候
                this.registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
                //为上下文初始化Message源,即不同语言的消息体,国际化处理
                this.initMessageSource();
                //初始化应用消息广播器,并放入ApplicationEventMulticaster中
                this.initApplicationEventMulticaster();
                //保留给子类来初始化其他bean
                this.onRefresh();
                //在所有注册的bean中查找Listener bean,注册到消息广播器中
                this.registerListeners();
                //初始化剩下的单实例(非懒加载的bean)
                this.finishBeanFactoryInitialization(beanFactory);
                //完成此上下文的刷新,调用 LifecycleProcessor 的 onRefresh() 方法并发布 ContextRefreshedEvent。
                this.finishRefresh();
             catch (BeansException var10) 
                if (this.logger.isWarnEnabled()) 
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
                

                this.destroyBeans();
                this.cancelRefresh(var10);
                throw var10;
             finally 
            //重置 Spring 核心中的常见自省缓存,因为我们可能不再需要单例 bean 的元数据......
                this.resetCommonCaches();
                contextRefresh.end();
            

        
    



AbstractApplicationContext#prepareRefresh—环境准备

	/**
准备此上下文以进行刷新、设置其启动日期和活动标志以及执行任何属性源的初始化。
	 */
	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());
			
		

		// 初始化上下文环境中的任何占位符属性源---该方法也是留给子类去覆盖的(例如:我们可以自定义占位符)
		initPropertySources();

		// 验证标记为必需的所有属性都是可解析的---需要的属性文件是否都已经放入环境中
		getEnvironment().validateRequiredProperties();
       
       
       //监听器的预处理
		// Store pre-refresh ApplicationListeners...
		//earlyApplicationListeners: 刷新前注册的本地侦听器
		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<>();
	

设置状态为激活,初始化属性源,验证必须的属性是否都是可解析的,预处理监听器


AbstractApplicationContext#obtainFreshBeanFactory—加载BeanFactory


//告诉子类刷新内部 bean 工厂。返回:新鲜的 BeanFactory 实例
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() 
	//初始BeanFactory,并对XML文件进行读取,并将得到的BeanFactory记录在当前实体的属性中
		refreshBeanFactory();
		//返回当前实体的BeanFactory属性
		return getBeanFactory();
	

AbstractRefreshableApplicationContext#refreshBeanFactory—初始化BeanFactory,读取xml啥的
	/**
	 * This implementation performs an actual refresh of this context's underlying
	 * bean factory, shutting down the previous bean factory (if any) and
	 * initializing a fresh bean factory for the next phase of the context's lifecycle.
	 */
	@Override
	protected final void refreshBeanFactory() throws BeansException 
	//因为ApplicationContext内部会拥有一个BeanFactory实例(又因为ApplicationContext继承了BeanFactory,个人感觉有点像装饰器模式)
	//这里判断当前ApplicationContext是否有旧的BeanFactory实例,如果有的话,就销毁BeanFactory工厂里面的单例bean,然后清空BeanFacotry
		if (hasBeanFactory()) 
			destroyBeans();
			closeBeanFactory();
		
		try 
		//创建DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
	   //为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象	
			beanFactory.setSerializationId(getId());
		//定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
			customizeBeanFactory(beanFactory);
			//初始DocumentReader,并进行XML文件读取及解析
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		
		catch (IOException ex) 
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		
	



ApplicationContext与BeanFactory的关系

在ApplicationContext内部会维护一个BeanFactory的实例,并且ApplicationContext继承了BeanFactory,这是不是很像设计模式中的装饰器模式

因此在我看来,spring在此处就是运用了装饰器模式,对BeanFactory完成了功能的扩展


AbstractRefreshableApplicationContext#createBeanFactory—创建bean工厂

创建的就是DefaultListableBeanFactory,getInternalParentBeanFactory()方法是在设置了父类容器的情况下才会返回非NULL结果

	protected DefaultListableBeanFactory createBeanFactory() 
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	

AbstractRefreshableApplicationContext#customizeBeanFactory—定制BeanFactory
//自定义此上下文使用的内部 bean 工厂。为每次 refresh() 尝试调用。
//默认实现应用此上下文的“allowBeanDefinitionOverriding”
//和“allowCircularReferences”设置(如果指定)。
//可以在子类中重写以自定义任何 DefaultListableBeanFactory 的设置。
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) 
	    //是否允许bean定义的覆盖
		if (this.allowBeanDefinitionOverriding != null) 
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		
		//是否允许循环依赖
		if (this.allowCircularReferences != null) 
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		
	

AbstractXmlApplicationContext#loadBeanDefinitions—加载BeanDefinition

	/**
	 * Loads the bean definitions via an XmlBeanDefinitionReader.
	 */
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException 
		//xml--->BeanDefinition
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		//允许子类提供阅读器的自定义初始化,然后继续实际加载 bean 定义。---这里只是简单对BeanDefinitionReader做个校验
		initBeanDefinitionReader(beanDefinitionReader);
		//这个方法比较重要
		loadBeanDefinitions(beanDefinitionReader);
	

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException 
		Resource[] configResources = getConfigResources();
		if (configResources != null) 
			reader.loadBeanDefinitions(configResources);
		
		String[] configLocations = getConfigLocations();
		if (configLocations != null) 
			reader.loadBeanDefinitions(configLocations);
		
	


AbstractApplicationContext#prepareBeanFactory—功能扩展

//配置工厂的标准上下文特征,例如上下文的 ClassLoader 和后处理器。
	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) 
		//设置ApplicationContext内部的BeanFactory使用当前context的classLoader
		beanFactory.setBeanClassLoader(getClassLoader());
		//指示 Spring 是否需要忽略 SpEL,即不初始化 SpEL 基础结构。
		//private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");
		//默认为false
		if (!shouldIgnoreSpel) 
		//默认支持SPEL功能--即可以用#bean.xxx来调用相关属性值
		//!!! 
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		
		
		//为BeanFactory增加一个ResourceEditorRegistrar
		//PropertyEditorRegistrar:属性编辑器的登记注册,该类用来注册相关属性编辑器
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		//添加BeanPostProcessor
		//这里默认添加的一个ApplicationContextAwareProcessor是用来处理实现aware接口的注入功能的
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		
		//设置了几个忽略自动装配的接口---如果我们想在程序中自动注入这些接口的话,显然不太行
		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.ignoreDependencyInterface(ApplicationStartupAware.class);

        //设置了几个自动装配的特殊规则---如果我们在程序中注入下面这个几个bean,是可以成功的
		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		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.
		//将用于检测内部 bean 的早期后处理器注册为 ApplicationListener。----检测实现 ApplicationListener 接口的 bean
		//如果找到这样的bean,并且是单例的,那么就可以添加进applicationListeners集合中去
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
        
        //增加对AspectJ的支持     
		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (!NativeDetector.inNativeImage() && 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.
		//添加系统默认的环境bean,并且是在不存在的情况下才会去添加
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) 
		//getEnvironment()默认返回Environent---这也是为什么我们可以直接注入使用
			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以上是关于Spring读源码系列06----容器扩展功能--上的主要内容,如果未能解决你的问题,请参考以下文章

Spring读源码系列08----容器扩展功能--下

Spring读源码系列番外篇---06----类型转换---下---ConversionService相关家族

Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义

Spring读源码系列01---Spring核心类及关联性介绍

Spring源码系列 — 容器Extend Point

Spring 源码分析--容器的功能扩展