三、Spring-ClassPathXmlApplicationContext构造分析

1.启动类

public class App {

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

}

2.类结构分析

ClassPathXmlApplicationContext继承了AbstractApplicationContext抽象类实现了BeanFactory接口。

3.构造函数分析

	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent); 
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

3.1 super(parent);

      这里的parent是空,里面一直会调用父类的构造函数,直到AbstractApplicationContext的构造函数。

public AbstractApplicationContext(@Nullable ApplicationContext parent) {
		this();  //赋值解析资源文件类
		setParent(parent);  //设置父容器
}

       this()方法里面会新建PathMatchingResourcePatternResolver解析器。

	public AbstractApplicationContext() {
		this.resourcePatternResolver = getResourcePatternResolver();
	}


    protected ResourcePatternResolver getResourcePatternResolver() {
		return new PathMatchingResourcePatternResolver(this);
	}

      PathMatchingResourcePatternResolver可以用来解析资源文件,主要是用来解析类路径下的资源文件。当然它也可以用来解析其它资源文件,如基于文件系统的本地资源文件。PathMatchingResourcePatternResolver在使用时可以直接new一个对象,new的时候可以通过使用带ResourceLoader参数的构造方法指定需要使用的ResourceLoader,解析好了资源后获取资源时需要通过ResourceLoader获取。PathMatchingResourcePatternResolver其实也是实现了ResourceLoader接口的。空的构造方法将使用DefaultResourceLoader获取资

源。

3.2  setConfigLocations(configLocations)

       这里configLocations参数我们传入的是classpath:spring.xml,这里作用是解析并赋值配置文件的路径,当然也初始化了系统环境Environment;

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++) {
                //这里会解析配置文件名字中包含一些占位符
                //spring-${spring.active}.xml
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}
}


protected String resolvePath(String path) {
        //解析配置文件名字
		return getEnvironment().resolveRequiredPlaceholders(path);
}

 

   getEnvironment()方法第一次调用会初始化StandardEnvironment环境配置类,StandardEnvironment继承关系:

父类:AbstractEnvironment构造方法,会初始化

     1.赋值MutablePropertySources 

     2.新建一个PropertySourcesPropertyResolver资源解析器

     3.调用定制化customizePropertySources方法。这里我们之类重新这个方法,来初始化系统环境信息。

  AbstractEnvironment:

protected AbstractEnvironment(MutablePropertySources propertySources) {
		this.propertySources = propertySources;
		this.propertyResolver = createPropertyResolver(propertySources);
		customizePropertySources(propertySources);
}

  StandardEnvironment:

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()));
	}
    resolveRequiredPlaceholders(path)方法会调用PropertySourcesPropertyResolver这个类,因为之前获取初始化环境的时候已经new出来了,这个方法会新建一个PropertyPlaceholderHelper解析类,来解析站位符号。

  新建PropertyPlaceholderHelper

public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
		if (this.strictHelper == null) {
			this.strictHelper = createPlaceholderHelper(false);
		}
		return doResolvePlaceholders(text, this.strictHelper);
}

 解析配置文件名占位符

PropertyPlaceholderHelper.class

	protected String parseStringValue(
			String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {

		int startIndex = value.indexOf(this.placeholderPrefix);
		if (startIndex == -1) {
			return value;
		}

		StringBuilder result = new StringBuilder(value);
		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 == null) {
					visitedPlaceholders = new HashSet<>(4);
				}
				if (!visitedPlaceholders.add(originalPlaceholder)) {
					throw new IllegalArgumentException(
							"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
				}
				// Recursive invocation, parsing placeholders contained in the placeholder key.
				placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
				// Now obtain the value for the fully resolved key...
				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();
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值