Spring IOC容器源码分析
1. 入口类
new ClassPathXmlApplicationContext(“spring.xml”);
直接采用读取classpath路径下xml的容器类
这个类依赖于xml文件的配置,同时需要的jar包是 context core 和 beans
分工:
context 负责容器
beans 负责根据xml注册的bean,也包括了注解注入注册的bean
core 一些工具类
1.1 new的时候发生了什么?spring做了哪些操作。
(1) 根据spring.xml名称初始化configLocation = spring.xml 构建一个数组
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
如果有多个配置文件,就自动构成一个加长数组
public ClassPathXmlApplicationContext(String… configLocations) throws BeansException {
this(configLocations, true, null);
}
将所有的初始化委托给了有参构造器
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
a.递归调用父类构造器
a1. 得到类加载器,依次是当前线程的类加载器Thread.currentThread.getContextLoader(),
加载委托类的加载器 ClassUtils.class.getClassLoader(),系统加载器ClassLoader.getSystemClassLoader
a2. 得到一个new PathMatchingResourcePatternResolver(this) 路径资源解析
a3. setParent(parent); 设置父类容器,null就没有了
b. 加载路径数组 setConfigLocations(configLocations);
b1. 取一个同样长度的数组,解析,返回字符串
this.configLocations[i] = resolvePath(locations[i]).trim();
b2. 创建了一个标准的环境对象 new StandardEnvironment();
getEnvironment().resolveRequiredPlaceholders(path);
b3. 委托给环境对象中的属性解析器进行解析 ConfigurablePropertyResolver 解析对象
this.propertyResolver.resolveRequiredPlaceholders(text);
b4. 创建了一个helper对象解析
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
if (this.strictHelper == null) {
this.strictHelper = createPlaceholderHelper(false);
}
return doResolvePlaceholders(text, this.strictHelper);
}
b5. 一路跟踪,调用这个方法,第二个参数回调函数(策略模式?)
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders)
打算用一个while循环来解析 value = spring.xml, 但这里的前缀是 ${ 为-1直接返回了”spring.xml” 字符串
StringBuilder result = new StringBuilder(value);
int startIndex = value.indexOf(this.placeholderPrefix);
while (startIndex != -1) {
——————–以上啥都没干—————
还是做了,初始化了解析对象,环境对象等,下面是一个刷新方法。应该就是其主要逻辑了。
if (refresh) {
refresh();
}
b6. synchronized (this.startupShutdownMonitor) { 要初始化需要加互斥锁
准备工作包含了开始时间戳,活动boolean true,关闭false,空的初始化属性。
// Prepare this context for refreshing.
prepareRefresh();
校验属性有没有异常,有的话会抛出,中止
getEnvironment().validateRequiredProperties();
用来存储更早的应用事件
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
创建一个beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
new DefaultListableBeanFactory(getInternalParentBeanFactory())
在该beanFactory中注册加载类,忽略的类,等
2. 入口方法
applicationContext.getBean(“dataSource”);