栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring源码解析(14)之refresh源码分析(二)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring源码解析(14)之refresh源码分析(二)

一、前言

        在上篇中Spring源码解析(13)之refresh源码分析(一)_jokeMqc的博客-CSDN博客我们已经介绍了ClassPathXmlApplicationContext前两个方法的作用,没有看到我上一篇的文章的可以先去看下上一篇对于ClassPathXmlApplicationContext的介绍。

        接下来我们就要对refresh方法的13个方法进行具体的源码分析了,首先我们先来看下refresh的大体代码;

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			
			prepareRefresh();
			
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			
			prepareBeanFactory(beanFactory);

			try {
				
				postProcessBeanFactory(beanFactory);

				
				invokeBeanFactoryPostProcessors(beanFactory);

				
				registerBeanPostProcessors(beanFactory);

				
				initMessageSource();

				
				initApplicationEventMulticaster();

				
				onRefresh();

				
				registerListeners();

				
				finishBeanFactoryInitialization(beanFactory);

				
				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.
				// 清空单实例bean对应的map及缓存
				destroyBeans();

				// 设置容器的活跃状态为false
				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();
			}
		}
	}

        接下来我们就一一对这个13个方法的源码进行分析。

1.1prepareRefresh

        prepareRefresh();做的事情比较简单:准备上下文,设置其启动日期和活动标志,执行属性源的初始化。

	protected void prepareRefresh() {
		// 记录容器的启动时间.
		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.
		
		initPropertySources();

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

		// Store pre-refresh ApplicationListeners...
		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<>();
	}

        前面主要是初始化一些标记位,然后我们看到initPropertySources这个方法,这个是Spring留给开发人员的一个扩展点,如果需要在验证系统属性之前,给系统中设置一些默认值。可以通过继承AbstractApplicationContext类,并重写该方法实现。如下:

public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {


    public MyClassPathXmlApplicationContext(String... configLocations){
        super(configLocations);
    }

    @Override
    protected void initPropertySources() {
        System.out.println("扩展initPropertySource");
        getEnvironment().setRequiredProperties("username");
    }
// ....忽略部分代码
}

        然后我们接下来看getEnvironment里面做了那些事情?

	@Override
	public ConfigurableEnvironment getEnvironment() {
        // 如果存在环境则直接返回,如果不存在则创建一个环境对象再返回
		if (this.environment == null) {
			// StandardEnvironment
			this.environment = createEnvironment();
		}
		return this.environment;
	}


	protected ConfigurableEnvironment createEnvironment() {
		return new StandardEnvironment();
	}


public class StandardEnvironment extends AbstractEnvironment {

	
	public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

	
	public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";


	
	@Override
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(
				new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(
				new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

}

        从源码可以看出,如果存在一个换进对象则直接返回,如果不存在一个环境对象在则创建一个再返回,然后默认的环境对象是StandardEnvironment,我们看到StandardEnvironment没有默认的构造方法,然后我们具体看他父类的构造方法,父类的构造方法调用了customizePropertySources方法也就是StandardEnvironment中的customizePropertySources方法,我们可以看得到这个方法就是为我们去加载一些系统变量跟环境变量,这个我们在上一篇中也有介绍到过。

        然后就是校验对应需要的属性存在不存在,如果不存在就抛出异常。

1.2obtainFreshBeanFactory

        获取Bean工厂,期间会做解析和加载bean定义的一些列工作.生成BeanDefinition对象。

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

        刷新bean工厂,判断bean工厂是否已经存在,如果存在需要进行销毁和关闭,我们接着继续往下看。

@Override
	protected final void refreshBeanFactory() throws BeansException {
		// 判断bean工厂是否存在,如果存在需要先销毁和关闭。否则会出现问题
		if (hasBeanFactory()) {
			// 销毁bean,根据bean的名称将bean工厂中的所有bean都从map中移除
			destroyBeans();
			// 关闭bean工厂,设置Bean工厂的序列化id为null,并将beanFactory的值赋值为null
			closeBeanFactory();
		}
		try {
			// 重新创建bean工厂,默认返回的是Bean工厂类型是:DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();

			// 设置序列化ID,ID: class名称 + "@" + 对象的十六进制值
			beanFactory.setSerializationId(getId());

			// 定制bean工厂。作用:设置bean定义是否可以被覆盖以及设置bean在创建的时候是否允许循环引用.
			customizeBeanFactory(beanFactory);

			// 解析并加载bean的定义,默认是通过AbstractXmlApplicationContext类中的loadBeanDefinitions实现
			loadBeanDefinitions(beanFactory);

			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

        refreshBeanFactory一共做了几件事情;

  1. 判断bean工厂是否存在,如果存在需要先销毁和关闭。否则会出现问题;
  2. 重新创建bean工厂,默认返回的是Bean工厂类型是:DefaultListableBeanFactory;
  3. 设置序列化ID,ID: class名称 + "@" + 对象的十六进制值;
  4. 定制bean工厂。作用:设置bean定义是否可以被覆盖以及设置bean在创建的时候是否允许循环引用.
  5. 解析并加载bean的定义,默认是通过AbstractXmlApplicationContext类中的loadBeanDefinitions实现;

        我们接下来看它是如果创建DefaultListableBeanFactory的。

    // AbstractRefreshableApplicationContext	
    protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

    // DefaultListableBeanFactory
	public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
		super(parentBeanFactory);
	}

    // AbstractAutowireCapableBeanFactory
    	public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
		this();
		setParentBeanFactory(parentBeanFactory);
	}

    
	
	public AbstractAutowireCapableBeanFactory() {
		super();

		// 在Bean自动装配时自动忽略BeanNameAware子类的注入
		ignoreDependencyInterface(BeanNameAware.class);

		// 忽略BeanFactoryAware接口子类的注入
		ignoreDependencyInterface(BeanFactoryAware.class);

		// 忽略BeanClassLoaderAware接口子类的注入
		ignoreDependencyInterface(BeanClassLoaderAware.class);
	}


        接下来看下customizeBeanFactory是如何定制BeanFactory的。

	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		// 是否允许覆盖Bean的定义
		if (this.allowBeanDefinitionOverriding != null) {
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// 该属性在解决Spring Bean的循环依赖中会使用到
		// 如果该属性的值为true,而且将要初始化的bean为单例,而且正在创建中,则在初始化属性前会把该bean的信息放入到singletonFactories中.
		if (this.allowCircularReferences != null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
	}

        两个属性,allowBeanDefinitionOverriding是否允许覆盖Bean的定义,allowCircularReferences该属性在解决Spring Bean的循环依赖中会使用到。

        接下来我们来看下loadBeanDefinitions,这里loadBeanDefinitions是一个重载方法大家看的时候不要被绕晕了。

	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// 创建Xml格式的Bean读取器,里面会设置bean工厂的资源加载器及环境信息
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// 对象创建bean读取器的时候已经初始化.此处直接获取
		beanDefinitionReader.setEnvironment(this.getEnvironment());

		// 上述创建时已经初始化,此处直接获取
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);

		// 会解析xml中的标签属性,并添加到bean定义中.
		loadBeanDefinitions(beanDefinitionReader);
	}

        他首先是创建Xml格式的Bean读取器,里面会设置bean工厂的资源加载器及环境信息,然后对beanDefinitionReader进行一些属性赋值,最后就会解析xml中的标签属性,并添加到bean定义中,我们具体看对应的解析源码;

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		// 通过另外一个构造函数构造的容器,会使用configResources的方式去加载bean定义
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		// 获取所有的配置文件名称,例如:{"beans.xml"}。主要是xml配置文件的名称
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

        很显然没有调用有他一下的这个构造方法:

	public ClassPathXmlApplicationContext(String[] paths, Class clazz, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		Assert.notNull(paths, "Path array must not be null");
		Assert.notNull(clazz, "Class argument must not be null");
		this.configResources = new Resource[paths.length];
		for (int i = 0; i < paths.length; i++) {
			this.configResources[i] = new ClassPathResource(paths[i], clazz);
		}
		refresh();
	}

        所以拿到的configResources 为null,我们就继续走下一个方法,获取所有的配置文件,然后把配置文件列表传进去解析。

	@Override
	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int count = 0;
		for (String location : locations) {
			// 加载bean定义
			count += loadBeanDefinitions(location);
		}
		return count;
	}

	@Override
	public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(location, null);
	}

	public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {

		// resourceLoader是在XmlApplicationContext中通过setResourceLoader方法设置进去的属性
		ResourceLoader resourceLoader = getResourceLoader();

		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
		}
		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				// 加载bean定义.
				int count = loadBeanDefinitions(resources);
				if (actualResources != null) {
					Collections.addAll(actualResources, resources);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
				}
				return count;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// Can only load single resources by absolute URL.
			Resource resource = resourceLoader.getResource(location);
			int count = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
			}
			return count;
		}
	}


        我们根据配置文件解析得出一个Resource[]数组,然后将这个Resource[]数组再传进去解析,我们接着往下看。


	
	@Override
	public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int count = 0;
		for (Resource resource : resources) {
			// 加载bean定义
			count += loadBeanDefinitions(resource);
		}
		return count;
	}

	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}



	
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}

		Set currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				// 执行bean定义加载
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}


protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			// 将xml配置文件通过JDK中的JAXP(Java API for XMLProcessing)解析为document对象
			document doc = doLoaddocument(inputSource, resource);
			// 注册bean定义
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		}
		catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		}
		catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}

	public int registerBeanDefinitions(document doc, Resource resource) throws BeanDefinitionStoreException {
		// 通过反射创建Bean定义文档读取器,默认类型为:DefaultBeanDefinitiondocumentReader
		BeanDefinitiondocumentReader documentReader = createBeanDefinitiondocumentReader();
		// 获取之前已经加载的bean定义数量,直接通过beanDefinitionMap.size获取
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 执行xml的解析及bean定义注册。在创建bean定义读取器上下文时,会去创建默认的DefaultNamespaceHandlerResolver
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		// 返回本次注册的bean定义的数量
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

      好了,今天先分析到prepareRefresh跟obtainFreshBeanFactory,后面我们接着继续往下分析。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/696614.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号