入口

常使用的入口

  1. public static void main(String[] args) {
  2. ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
  3. }

我们看一下 ClassPathXmlApplicationContext 的构造函数:
ClassPathXmlApplicationContext.java

  1. public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
  2. this(new String[]{configLocation}, true, (ApplicationContext)null);
  3. }

发现我们最终调用的构造函数是:
ClassPathXmlApplicationContext.java

  1. public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
  2. super(parent);
  3. this.setConfigLocations(configLocations);
  4. if (refresh) {
  5. this.refresh();
  6. }
  7. }

通过构造函数,我们可以分析出创建 ClassPathXmlApplicationContext 容器时,构造函数做了以下事情:

  1. 调用父容器的构造方法 super(parent) ,为容器设置好Bean 资源解析器;
  2. 调用父类 AbstractRefreshableConfigApplicationContextsetConfigLocations(configLocations) 方法,设置Bean 配置信息的定位路径;
  3. 调用 refresh() 方法。

设置Bean 资源加载器

通过追踪 super(parent) ,发现 AbstractApplicationContext 最终的构造函数:
AbstractApplicationContext.java

  1. public abstract class AbstractApplicationContext
  2. extends DefaultResourceLoader
  3. implements ConfigurableApplicationContext{
  4. public AbstractApplicationContext() {
  5. this.logger = LogFactory.getLog(this.getClass());
  6. this.id = ObjectUtils.identityToString(this);
  7. this.displayName = ObjectUtils.identityToString(this);
  8. this.beanFactoryPostProcessors = new ArrayList();
  9. this.active = new AtomicBoolean();
  10. this.closed = new AtomicBoolean();
  11. this.startupShutdownMonitor = new Object();
  12. this.applicationListeners = new LinkedHashSet();
  13. // 获取一个spring source 的资源解析器
  14. this.resourcePatternResolver = this.getResourcePatternResolver();
  15. }
  16. public AbstractApplicationContext(@Nullable ApplicationContext parent) {
  17. this();
  18. this.setParent(parent);
  19. }
  20. // 获取一个spring source 的资源解析器用于读取Spring Bean 信息
  21. protected ResourcePatternResolver getResourcePatternResolver() {
  22. return new PathMatchingResourcePatternResolver(this);
  23. }
  24. }

调用 PathMatchingResourcePatternResolver 的构造函数来创建Spring 资源加载器:

PathMatchingResourcePatternResolver.java

  1. public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
  2. Assert.notNull(resourceLoader, "ResourceLoader must not be null");
  3. // 设置Spring 资源加载器
  4. this.resourceLoader = resourceLoader;
  5. }

这里需要注意的是: AbstractApplicationContext 继承 DefaultResourceLoader ,因此也是一个资源加载器,所以能够作为参数。

Bean 配置信息的定位

在设置Bean 资源解析器之后,接下来 ClassPathXmlApplicationContext 通过调用父类 AbstractRefreshableConfigApplicationContextsetConfigLocations(configLocations) 方法,设置Bean 配置信息的定位路径.。该方法的源码如下:
AbstractRefreshableConfigApplicationContext.java

  1. // 处理多个资源文件路径为一个字符串的情况
  2. public void setConfigLocation(String location) {
  3. // 按照",; \t\n",将多个资源文件路径进行分割,解析为数组形式
  4. this.setConfigLocations(StringUtils.tokenizeToStringArray(location, ",; \t\n"));
  5. }
  6. // 解析Bean 定义资源文件的路径,处理多个文件字符串数组
  7. public void setConfigLocations(@Nullable String... locations) {
  8. if (locations != null) {
  9. Assert.noNullElements(locations, "Config locations must not be null");
  10. this.configLocations = new String[locations.length];
  11. for(int i = 0; i < locations.length; ++i) {
  12. // resolvePath 为将字符串解析为路径的方法
  13. this.configLocations[i] = this.resolvePath(locations[i]).trim();
  14. }
  15. } else {
  16. this.configLocations = null;
  17. }
  18. }

从以上两个方法我们可以看出:我们既可以使用一个字符串来配置多个Spring Bean 资源文件信息,也可以用字符串数组进行配置。多个资源文件路径之间是可以使用“,;\t\n”进行分割。

refresh() 方法开始启动