spring ioc源码解析0解析入口-基于ClassPathXmlApplicationContext读取配置文件方式

1.入口

	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
	}

2.ClassPathXmlApplicationContext类图分析一下:

3.详细解析

	/**
	 * 读取一个配置文件的构造方法
	 */
	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

	/**
	 * 构造方法 
	 * @param configLocations	配置文件列表
	 * @param refresh	是否刷新
	 * @param parent	父容器
	 */
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);	//调用父类构造方法,传入parent  这里为null
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

3.1 super方法详解

向上追溯

	public AbstractXmlApplicationContext(@Nullable ApplicationContext parent) {
		super(parent);
	}
//===================================================================================
	public AbstractRefreshableConfigApplicationContext(@Nullable ApplicationContext parent) {
		super(parent);
	}
//===================================================================================
	public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {
		super(parent);
	}
//===================================================================================
	public AbstractApplicationContext(@Nullable ApplicationContext parent) {
		this();
		setParent(parent);
	}
//===================================================================================
	public AbstractApplicationContext() {
		this.resourcePatternResolver = getResourcePatternResolver();
	}
	protected ResourcePatternResolver getResourcePatternResolver() {
		return new PathMatchingResourcePatternResolver(this);
	}

	/**
	 * 设置parent
	 */
	@Override
	public void setParent(@Nullable ApplicationContext parent) {
		this.parent = parent;	//设置parent
		if (parent != null) {	//为空则不做处理
			Environment parentEnvironment = parent.getEnvironment();
			if (parentEnvironment instanceof ConfigurableEnvironment) {
				getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
			}
		}
	}

总结:

1.将AbstractApplicationContext中resourcePatternResolver属性初始化成PathMatchingResourcePatternResolver对象实例

2.将父容器parent置空

3.2 setConfigLocations方法详解

	/**
	 * 将路径赋值给configLocations.
	 */
	public void setConfigLocations(@Nullable String... locations) {
		if (locations != null) {
			Assert.noNullElements(locations, "Config locations must not be null");//校验数组中的值,不能未null
			this.configLocations = new String[locations.length];
	                // 1.遍历解析locations
			for (int i = 0; i < locations.length; i++) {
	                        // 2.解析给定路径,必要时用相应的环境属性值替换占位符
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}
	}

3.2.1 Assert.noNullElements

	public static void noNullElements(@Nullable Object[] array, String message) {
		if (array != null) {
			for (Object element : array) {
				if (element == null) {
					throw new IllegalArgumentException(message);
				}
			}
		}
	}

3.2.2 resolvePath

	/**
	 * 解析给定路径,必要时用相应的环境属性值替换占位符
	 */
	protected String resolvePath(String path) {
	    // 1.getEnvironment:获取环境属性
	    // 2.resolveRequiredPlaceholders: 解析给定路径,必要时用相应的环境属性值替换占位符,例如${path}
	    return getEnvironment().resolveRequiredPlaceholders(path);
	}

3.3refresh方法详解

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		//startupShutdownMonitor对象在spring环境刷新和销毁的时候都会用到,确保刷新和销毁不会同时执行
		synchronized (this.startupShutdownMonitor) {
			// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
			prepareRefresh();

			/*
			 * 用于获得一个新的 BeanFactory
			 * 	该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。
			 * 	常见的,如果解析到<context:component-scan base-package="com.joonwhee.open" /> 注解时,会扫描 base-package 指定的目录,
			 * 		将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的 bean 定义也同样封装成 BeanDefinition,加载到 BeanFactory 中。
			 * 	上面提到的“加载到 BeanFactory 中”的内容主要指的是以下3个缓存:
			 * 		beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合。
			 * 		beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射。
			 * 		aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			/*
			 * 配置 beanFactory 的标准上下文特征,例如上下文的 ClassLoader、后置处理器等。这个方法会注册3个默认环境
			 * 	bean:environment、systemProperties 和 systemEnvironment,
			 * 	注册 2 个 bean 后置处理器:ApplicationContextAwareProcessor 和 ApplicationListenerDetector。
			 */
			prepareBeanFactory(beanFactory);

			try {
				/* 允许子类对 BeanFactory 进行后续处理,默认实现为空,留给子类实现。 */
				postProcessBeanFactory(beanFactory);

				// 激活BeanFactory的处理器 
				/*
				 * 实例化和调用所有 BeanFactoryPostProcessor,包括其子类 BeanDefinitionRegistryPostProcessor。
				 * BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 
				 * BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
				 * 
				 * BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,
				 * 	主要用来在常规的 BeanFactoryPostProcessor 激活之前注册一些 bean 定义。特别是,
				 * 	你可以通过 BeanDefinitionRegistryPostProcessor来注册一些常规的 BeanFactoryPostProcessor,
				 * 	因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。 
				 * 
				 * 注:这边的 “常规 BeanFactoryPostProcessor” 主要用来跟 BeanDefinitionRegistryPostProcessor 区分。
				 */
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册拦截Bean创建的Bean处理器
				/*
				 * 注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
				 * BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,
				 * Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。
				 * 在这边只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。
				 * 
				 * 具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,
				 * 	执行初始化方法后会调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法。
				 */
				registerBeanPostProcessors(beanFactory);

				// 为上下文初始化Message源(初始化消息资源 MessageSource)
				initMessageSource();

				// 初始化应用消息广播器(初始化应用的事件广播器 ApplicationEventMulticaster)
				initApplicationEventMulticaster();

				// 该方法为模板方法,提供给子类扩展实现,可以重写以添加特定于上下文的刷新工作,默认实现为空。
				onRefresh();

				// 查找Listeners bean,注册到消息广播器中(注册监听器)
				registerListeners();

				// 初始化剩下的单实例
				/*
				 * 该方法会实例化所有剩余的非懒加载单例 bean。
				 * 	除了一些内部的 bean、实现了 BeanFactoryPostProcessor 接口的 bean、实现了BeanPostProcessor 接口的 bean,
				 * 	其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。
				 */
				finishBeanFactoryInitialization(beanFactory);

				// 完成刷新过程,通知生命周期处理器
				/* 完成此上下文的刷新,主要是推送上下文刷新完毕事件(ContextRefreshedEvent )到监听器 */
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 刷新失败后的处理,主要是将一些保存环境信息的集合做清理
				destroyBeans();

				// applicationContext是否已经激活的标志,设置为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();
			}
		}
	}

详细每个方法的解析下次再说

猜你喜欢

转载自blog.csdn.net/luo_mu_hpu/article/details/107313378
今日推荐