Spring启动流程解析,基于ClassPathXmlApplicationContext

记录一下学习Spring源码 基于Spring5.1.3RELEASE

一.基础代码

1.基础的项目目录截图如下
在这里插入图片描述
2.bean.xml

    <bean class="com.lixiao.stydy.spring.domain.Student" id="lixiao">
        <property name="name" value="李校"></property>
        <property name="age" value="18"></property>
        <property name="father" value="爸爸"></property>
        <property name="mother" value="妈妈"></property>
    </bean>

3.main方法

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student lixiao = context.getBean("lixiao", Student.class);
        System.out.println(lixiao.getName());
二、源码分析
1.ClassPathXmlApplicationContext 构造器
	/*
		参数说明:1.String[] configLocations 这个是一个配置数组 例如"beans.xml"
				2.boolean refresh 是否refresh 默认是true
				3.@Nullable ApplicationContext parent 可以为空的父容器
	*/
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, 
			@Nullable ApplicationContext parent)
			throws BeansException {
		/** 
		  * 如果有父容器就先执行这个方法,核心是一个合并方法,把父类的配置全部赋值到当前容器中
		  * 会先放全部的配置PropertySources  再放被active的配置ActiveProfiles 再放默认配置
		  * DefaultProfiles
		  * 作用可以参考这里 https://www.cnblogs.com/jason0529/p/6567373.html
		  */
		super(parent);
		/**1.处理占位符,例如spring${username}.xml 他会从系统环境和jvm环境中取值,如果windows
		 * 系统填username那最后解析出来的就是你当前计算机的用户名称,例如我的是李校 C:\Users\李校
		 * 2.加载当前的操作系统环境和JVM环境
		 * 可以参考这里https://blog.csdn.net/huzhiliayanghao/article/details/115256071
		 */
		setConfigLocations(configLocations);
		if (refresh) {
		  //最核心的方法,把这个搞明白Spring应该就清楚了
			refresh();
		}
	}
2.refresh()方法
public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			/**
				准备refresh工作
				1.记录启动时间为当前时间,记录启动状态为true,记录关闭状态为false
				2.打印日志
				3.放一个初始化环境资源的空方法,留给子类覆盖
				使用参考:https://blog.csdn.net/u013277209/article/details/109177452
				4.创建并获取环境对象,验证需要的属性文件是否都已经放入环境中 这个就配合3使用,如果
				使用了3 启动之后如果没读取到3的配置这里就会抛出异常
				5.创建刷新前的监听事件集合
			*/
			prepareRefresh();

			/*
				刷新并获取beanFactory
				1.如果存在beanFactory就先销毁beanFactory
				2.new一个DefaultListableBeanFactory
				3.设置beanFactior的序列号ID为当前容器对象的信息
				   例如@asdvb 就是@+16进制的hashCode
				4.留一个扩展 用来设置 是否允许覆盖同名称的不同定义的对象,
				  是否允许bean之间的循环依赖。
				参考:https://blog.csdn.net/u013277209/article/details/109183125
				5.读取配置文件的bean的name,放到beanDefinitionsName这个list里面去
				  读取配置文件的bean完整信息放到beanDefinitionsMap 这个map里面去
			*/
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			/*
				准备beanFactory
				1.设置类加载器默认是当前容器的类加载器,根据类加载器设置表达式解析器默认是#{},
				  设置属性注册编辑器(读取xml里面bean的属性,当某些格式不支持读取的时候可以
				  自定义扩展),
				  可以参考
				  https://blog.csdn.net/cuichunchi/article/details/90407632
				2.给postProcesser添加aware和广播事件
			    3.忽略一些自动装配接口
			    4.添加自动装配的类
			    5.如果当前BeanFactory包含loadTimeWeaver Bean,说明存在类加载期织入AspectJ,
			    则把当前BeanFactory交给类加载期BeanPostProcessor实现类
			    LoadTimeWeaverAwareProcessor来处理,从而实现类加载期织入AspectJ的目的。
			    6.注册系统配置bean  environment,systemProperties,systemEnvironment
			*/ 
			prepareBeanFactory(beanFactory);

			try {
				//空方法,用来改变beanDefinitionsMap里面的bean信息,例如单例原型,属性值等
				//可以参考这个链接:
				//https://blog.csdn.net/caihaijiang/article/details/35552859
				postProcessBeanFactory(beanFactory);

				//执行实现了BeanFactoryPostProcessor接口的方法,就是上一步所添加的扩展点
				invokeBeanFactoryPostProcessors(beanFactory);

				//执行实现了BeanPostProcessor接口的方法
				registerBeanPostProcessors(beanFactory);

				//初始化国际化的东西
				initMessageSource();

				//初始化当前容器的事件广播器,如果用户定义了就用用户的,用户没定义就用默认的
				//就是if判断当前beanFactory
				//beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
				initApplicationEventMulticaster();

				//扩展点 子类重写这个方法,在容器刷新的时候可以自定义逻辑;
				//如创建Tomcat,Jetty等WEB服务器
				//参考:https://www.cnblogs.com/grasp/p/11942735.html
				onRefresh();

				//注册实现了ApplicationListener接口的监听器bean到
				//ApplicationEventMulticaster里面
				registerListeners();

				// 初始化所有剩下的非懒加载的单例bean
				finishBeanFactoryInitialization(beanFactory);

				//完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,
				//并且发布事件(ContextRefreshedEvent)
				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.
				destroyBeans();

				// Reset 'active' flag.
				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();
			}
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值