Spring源码解析(一)

面试中问的最多的就是你看过xxx源码嘛,我TM就想一jio过去,你工作中不是curd么,CV大法么,要看源码干什么。对,一开始我jio得看源码没什么用。面试官一开始叫我看源码,我是拒绝的,我不能因为你要问,我就要看啊,我得先试试,后来我试了之后发现,这效果duangduangduang的,诶呀,真香!
现在上主题,spring源码的真香定理开课了。

ClassPathXmlApplicationContext applicationContext =new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
applicationContext.getBean("");

进入ClassPathXmlApplicationContext 有参构造

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
	this(new String[] {configLocation}, true, null);
}
//	 进入this(new String[] {configLocation}, true, null)方法
public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		//1.初始化父类,设置PathMatchingResourcePatternResolver(资源查找器,主要是获取资源文件的时候可以解析*,?等符号的路径)
		super(parent);
		//2.设置本地的配置信息
		setConfigLocations(configLocations);
		//3.spring容器的初始化
		if (refresh) {
			refresh();
		}
}

真正调用的就是ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent),它做了三件大事。

1.初始化父类

设置PathMatchingResourcePatternResolver(资源查找器,主要是获取资源文件的时候可以解析*,?等符号的路径)
跟踪源码super(parent);

//这里是初始化AbstractXmlApplicationContext
public AbstractXmlApplicationContext(@Nullable ApplicationContext parent) {
		super(parent);
}
//继续跟踪super(parent);
//初始化AbstractRefreshableConfigApplicationContext
public AbstractRefreshableConfigApplicationContext(@Nullable ApplicationContext parent) {
		super(parent);
}
//继续跟踪super(parent);
//初始化AbstractRefreshableApplicationContext
public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {
		super(parent);
}
//继续跟踪super(parent);
//初始化AbstractApplicationContext
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
		//定义了一个资源查找器
		this();
		//ClassPathXmlApplicationContext 中的有参构造parent为null,所以这里啥也没干
		setParent(parent);
}

走到这里是不是感觉要晕了,所以,我们来一张类继承图,看看
在这里插入图片描述
然后继续跟踪this()方法

//跟踪this()
public AbstractApplicationContext() {
	//为内部一个获取资源的属性赋值
	this.resourcePatternResolver = getResourcePatternResolver();
}
//getResourcePatternResolver()
protected ResourcePatternResolver getResourcePatternResolver() {
	//PathMatchingResourcePatternResolver这里就是真正的资源查找器,获取资源getResource方法就是用他的
	return new PathMatchingResourcePatternResolver(this);
}

资源查找器PathMatchingResourcePatternResolver,我们看一下他的类继承图
在这里插入图片描述
ResourceLoader是spring定义的一个资源加载器接口,ResourcePatternResolver是可以查找"classpath*:"的这种格式的,而PathMatchingResourcePatternResolver这个资源查找器就比较强大,可以加载"classpath*:applicationContext-*.xml"这种格式,也就是我们xml中配置的加载文件context:property-placeholde这个标签中的通配符的资源文件,当然,既然是孙子类,儿子和爷爷的功能他也可以有的。说了一大堆,其实就是告诉你,设置了个资源查找器,你要调用getResource方法就是用他的。
AbstractApplicationContext这个中不是还有个方法么,啥也没干的方法setParent(parent);,看看。

//就是判断了下parent是不是空,是空就啥也没干
public void setParent(@Nullable ApplicationContext parent) {
		this.parent = parent;
		if (parent != null) {
			Environment parentEnvironment = parent.getEnvironment();
			if (parentEnvironment instanceof ConfigurableEnvironment) {
				getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
			}
		}
	}

补充说明,这里父类定义大量的模板,让子类实现,父类层层传递到子类 知道某个子类重载了抽象方法。这里应用到了职责链设计模式和模板设计模式。

2.设置本地的配置信息

跟踪源码setConfigLocations(configLocations);

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++) {
			//循环取出每一个path参数,在此处就一个"applicationContext.xml"
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}
}
//跟踪resolvePath(locations[i])
protected String resolvePath(String path) {
	//两部分,getEnvironment()创建环境对象StandardEnvironment,resolveRequiredPlaceholders(path)就是替换${}这样的值,就像你xml中引入另外一个文件,然后你会用${}一样,不过这里是从环境变量中去替换占位符
	return getEnvironment().resolveRequiredPlaceholders(path);
}
//跟踪getEnvironment()
public ConfigurableEnvironment getEnvironment() {
		if (this.environment == null) {
			this.environment = createEnvironment();
		}
		return this.environment;
}
//继续跟踪createEnvironment()
//实例化一个StandardEnvironment
protected ConfigurableEnvironment createEnvironment() {
		return new StandardEnvironment();
}

这里比较有意思的是,你以为他就是实例化一个StandardEnvironment,啥也没干,其实不是,继续跟踪看一看,发现
StandardEnvironment没有无参构造。

public class StandardEnvironment extends AbstractEnvironment {

	/** System environment property source name: {@value} */
	public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

	/** JVM system properties property source name: {@value} */
	public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
	
	@Override
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

}

没有那就证明无参构造用的是父类AbstractEnvironment的,那来看看父类AbstractEnvironment的无参构造

private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);

public AbstractEnvironment() {
		customizePropertySources(this.propertySources);
		if (logger.isDebugEnabled()) {
			logger.debug("Initialized " + getClass().getSimpleName() + " with PropertySources " + this.propertySources);
		}
}

无参构造又调用了customizePropertySources(this.propertySources);而propertySources就是 new MutablePropertySources(this.logger)。
这里解释一下MutablePropertySources,这个是什么,这个是PropertySources的实现类,而PropertySources又是继承了Iterable<PropertySource<?>>,PropertySource又是什么?PropertySource是一个抽象类,它包含一个source和一个name。source可以是map或其他,通常是一组键值对。PropertySource有个实现类MapPropertySource,而MutablePropertySources包含了一个CopyOnWriteArrayList集合,用来包含多个PropertySource。

private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();

很抽象是不是,没关系,用一个结构解释。

		Map<String,Object> map1=new HashMap<>();
		map1.put("systemProperties","我是Java进程变量");
		Map<String,Object> map2=new HashMap<>();
		map2.put("systemEnvironment","我是系统环境变量");
		PropertySource source1=new MapPropertySource("person",map1);
		PropertySource source2=new MapPropertySource("person",map2);
		List<PropertySource> list =new ArrayList<PropertySource>();
		list.add(source1);
		list.add(source2);

上图这个List list就相当于MutablePropertySources,相当于但是不等于,只是模拟让你稍微理解一下。

customizePropertySources(this.propertySources)方法AbstractEnvironment是空实现,啥也没有,所以这样是调用的StandardEnvironment的,也就是上面StandardEnvironment 唯一的一个方法

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

因为上面我模拟了一下数据结构,那这里猜一下也知道是首先向propertySources添加一组属性,来自Java进程变量(getSystemProperties()内是System.getProperties()方法);接着向propertySources再添加一组属性,来自系统环境变量(getSystemEnvironment()内是System.getenv()方法);
getSystemProperties和getSystemEnvironment方法中有个相同的细节需要注意,在获取进程变量或者系统环境变量的时候,都有可能因为安全限制抛出异常,这时候就返回一个ReadOnlySystemAttributesMap的实现类,外部调用get方法的时候,再去尝试获取进程变量或者系统环境变量对应的值,取不到则返回null

@Override
	@SuppressWarnings({"unchecked", "rawtypes"})
	public Map<String, Object> getSystemProperties() {
		try {
			return (Map) System.getProperties();
		}
		catch (AccessControlException ex) {
			return (Map) new ReadOnlySystemAttributesMap() {
				@Override
				@Nullable
				protected String getSystemAttribute(String attributeName) {
					try {
						return System.getProperty(attributeName);
					}
					catch (AccessControlException ex) {
						if (logger.isInfoEnabled()) {
							logger.info("Caught AccessControlException when accessing system property '" +
									attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());
						}
						return null;
					}
				}
			};
		}
	}

	@Override
	@SuppressWarnings({"unchecked", "rawtypes"})
	public Map<String, Object> getSystemEnvironment() {
		if (suppressGetenvAccess()) {
			return Collections.emptyMap();
		}
		try {
			return (Map) System.getenv();
		}
		catch (AccessControlException ex) {
			return (Map) new ReadOnlySystemAttributesMap() {
				@Override
				@Nullable
				protected String getSystemAttribute(String attributeName) {
					try {
						return System.getenv(attributeName);
					}
					catch (AccessControlException ex) {
						if (logger.isInfoEnabled()) {
							logger.info("Caught AccessControlException when accessing system environment variable '" +
									attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());
						}
						return null;
					}
				}
			};
		}
	}

系统环境搞定了,接下来是处理占位符了,跟踪一下resolveRequiredPlaceholders(path)

	public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
		return this.propertyResolver.resolveRequiredPlaceholders(text);
	}
//this.propertyResolver
private final ConfigurablePropertyResolver propertyResolver =
			new PropertySourcesPropertyResolver(this.propertySources);
//new PropertySourcesPropertyResolver(this.propertySources)就是设置了下环境变量的propertySources
	public PropertySourcesPropertyResolver(@Nullable PropertySources propertySources) {
		this.propertySources = propertySources;
	}	

这里PropertySourcesPropertyResolver的类继承图看一看
在这里插入图片描述
PropertyResolver实现这个类的接口具有解析PropertySource、根据PropertySource转换文本中的占位符的能力
一段代码说明

		Map<String,Object> map1=new HashMap<>();
		map1.put("name","zhangsan");
		PropertySource source=new MapPropertySource("person",map1);
		MutablePropertySources sources = new MutablePropertySources();
		sources.addLast(source);
		PropertyResolver resolver = new PropertySourcesPropertyResolver(sources);
		System.out.println(resolver.containsProperty("name"));//输出 zhangsan
		System.out.println(resolver.resolvePlaceholders("My name is ${name} "));//输出My name is zhangsan

接下来看resolveRequiredPlaceholders(text)方法,因为PropertySourcesPropertyResolver没有实现这个方法,所以在父类AbstractPropertyResolver中找到了

@Override
	public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
		if (this.strictHelper == null) {
			this.strictHelper = createPlaceholderHelper(false);
		}
		return doResolvePlaceholders(text, this.strictHelper);
	}
//this.strictHelper
private PropertyPlaceholderHelper strictHelper;
//createPlaceholderHelper(false)定义一个PropertyPlaceholderHelper,并传参数用于判断是否忽略不能解析的变量
private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
		return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix,
				this.valueSeparator, ignoreUnresolvablePlaceholders);
	}
//doResolvePlaceholders(text, this.strictHelper)
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
		//找到字符串中的占位符,调用PropertyResolver.getPropertyAsRawString方法,从环境变量中取出占位符对应的值,用环境变量的值替换占位符
		return helper.replacePlaceholders(text, this::getPropertyAsRawString);
}

helper.replacePlaceholders(text, this::getPropertyAsRawString);作用其实就是找到字符串中的占位符,调用PropertyResolver.getPropertyAsRawString方法,从环境变量中取出占位符对应的值,用环境变量的值替换占位符,比如classpath*:applicationContext-${profile}.xml替换为系统中profile的值
getPropertyAsRawString方法就是在propertySources中找值:

//getPropertyAsRawString AbstractPropertyResolver空实现,所以看子类PropertySourcesPropertyResolver
protected String getPropertyAsRawString(String key) {
		return getProperty(key, String.class, false);
	}
//getProperty(key, String.class, false)
//找到占位符key对应的value
	@Nullable
	protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
		if (this.propertySources != null) {
			for (PropertySource<?> propertySource : this.propertySources) {
				if (logger.isTraceEnabled()) {
					logger.trace("Searching for key '" + key + "' in PropertySource '" +
							propertySource.getName() + "'");
				}
				Object value = propertySource.getProperty(key);
				if (value != null) {
					if (resolveNestedPlaceholders && value instanceof String) {
						value = resolveNestedPlaceholders((String) value);
					}
					logKeyFound(key, propertySource, value);
					return convertValueIfNecessary(value, targetValueType);
				}
			}
		}
		if (logger.isDebugEnabled()) {
			logger.debug("Could not find key '" + key + "' in any property source");
		}
		return null;
	}

replacePlaceholders方法就是替换:

	public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
		Assert.notNull(value, "'value' must not be null");
		return parseStringValue(value, placeholderResolver, new HashSet<>());
	}
	
	//parseStringValue(value, placeholderResolver, new HashSet<>())
		protected String parseStringValue(
			String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {

		StringBuilder result = new StringBuilder(value);

		int startIndex = value.indexOf(this.placeholderPrefix);
		while (startIndex != -1) {
			int endIndex = findPlaceholderEndIndex(result, startIndex);
			if (endIndex != -1) {
				String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
				String originalPlaceholder = placeholder;
				if (!visitedPlaceholders.add(originalPlaceholder)) {
					throw new IllegalArgumentException(
							"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
				}
				 //这里有迭代操作,确保处理完字符串中所有的占位符
				placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
				 // 这里实际上会调用PropertySourcesPropertyResolver.getPropertyAsRawString方法,propVal的值就是从环境变量中取得的值
				String propVal = placeholderResolver.resolvePlaceholder(placeholder);
				if (propVal == null && this.valueSeparator != null) {
					int separatorIndex = placeholder.indexOf(this.valueSeparator);
					if (separatorIndex != -1) {
						String actualPlaceholder = placeholder.substring(0, separatorIndex);
						String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
						propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
						if (propVal == null) {
							propVal = defaultValue;
						}
					}
				}
				if (propVal != null) {
					// Recursive invocation, parsing placeholders contained in the
					// previously resolved placeholder value.
					propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
					result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
					if (logger.isTraceEnabled()) {
						logger.trace("Resolved placeholder '" + placeholder + "'");
					}
					startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
				}
				else if (this.ignoreUnresolvablePlaceholders) {
					// Proceed with unprocessed value.
					startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
				}
				else {
					throw new IllegalArgumentException("Could not resolve placeholder '" +
							placeholder + "'" + " in value \"" + value + "\"");
				}
				visitedPlaceholders.remove(originalPlaceholder);
			}
			else {
				startIndex = -1;
			}
		}

		return result.toString();
	}

总结一下
1.初始化AbstractXmlApplicationContext,AbstractRefreshableConfigApplicationContext,AbstractRefreshableApplicationContext,AbstractApplicationContext,在AbstractApplicationContext设置属性值ResourcePatternResolver资源获取的类为PathMatchingResourcePatternResolver,主要是为了我们获取资源的时候可以解析通配符。
2.在AbstractRefreshableConfigApplicationContext中实例化一个StandardEnvironment,在StandardEnvironment其父类AbstractEnvironment 中有个属性MutablePropertySources分别存放了系统环境和java环境的键值对。给AbstractEnvironment属性ConfigurablePropertyResolver初始化为PropertySourcesPropertyResolver类,在其父类AbstractPropertyResolver中创建PropertyPlaceholderHelper,然后PropertyPlaceholderHelper中在用环境变量的值替换占位符

欲知spring初始化如何,请听下回分解…
Spring源码解析(二)
在这里插入图片描述

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小明程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值