1.测试方法代码
public class Config {
public static void main(String args[]) {
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:application-config.xml");
System.out.println(applicationContext.getBean(HelloService.class).sayHello());
}
}
2.什么是application。
application就是我们所谓的上下文,容器。
FileSystemXmlApplicationContext是application的一个具体实现。spring中有许多application的不同实现,如ClassPathXmlApplicationContext,AnnotationConfigApplicationContext。下面我们先从FileSystemXmlApplicationContext开始入手。
3.结构如图所示
image.png
从上图的结构来看。其实整个容器是由几部分组成的。分别为ResourceLoader, BeanFactory, ApplicationEventPublisher, EnvironmentCapable, Lifecycle, Closeable。
分别介绍几个概念,ResourceLoader资源加载器,其中我们的类,class文件其实便是资源,资源加载器就是负责去加载资源, 至于根据什么去找到资源,那便是路径。那么有ResourceLoader便会有Resouce,那么resouce怎么跟bean关联起来呢,ResourceLoader便是将加载到的resouce转换成beandefinition, 最后再注册到beanfactory中去。这里只是讲解一下概念,后续会细致一点讲。
AbstractApplicationContext是一个核心抽象类,实现了大部分的功能,剩下的交由子类去实现。
4.可能3讲的很抽象,那么下面从代码入手吧。
先看会之前的测试代码
public class Config {
public static void main(String args[]) {
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:application-config.xml");
System.out.println(applicationContext.getBean(HelloService.class).sayHello());
}
}
为什么选择FileSystemXmlApplicationContext呢,其实AbstractXmlApplicationContext有多个实现类,所以随便挑一个进行讲解,其实ClassPathXmlApplicationContext也是大体功能是一样的。
那么好了,进入主题,先从构造方法入手吧。
/**
* Create a new FileSystemXmlApplicationContext, loading the definitions
* from the given XML file and automatically refreshing the context.
* @param configLocation file path
* @throws BeansException if context creation failed
*/
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
/**
* Create a new FileSystemXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of file paths
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public FileSystemXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);//此处主要作用是将自身作为一个路径解析器的变量,并且注入到父类中
setConfigLocations(configLocations);//此处是将路径保存到父类中去
if (refresh) {//是否需要刷新
refresh();//刷新容器---这里其实才是核心逻辑
}
}
先从构造方法参数的定义来看public FileSystemXmlApplicationContext(String configLocation),该构造方法上方的注解,创建一个新的FileSystemXmlApplicationContext,从码农给予的xml文件加载definitions,并且自动刷新容器。definitions其实是bean的一个包装类,记载了bean的相关信息。
接下来看其内部调用的构造方法,public FileSystemXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)。这里总共分为三个方法讲解,分别为 super(parent), setConfigLocations(configLocations), refresh()
首先从super(parent)看起
public FileSystemXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);//此处主要作用是将自身作为一个路径解析器的变量,并且注入到父类
。。。。。。下面的代码暂时忽略
}
最终到达的父类AbstractApplicationContext位置,this是一开始新建的FileSystemXmlApplicationContext实例
AbstractApplicationContext中的
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext{
private ResourcePatternResolver resourcePatternResolver;
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
}
那么PathMatchingResourcePatternResolver类的结构是怎么样的呢?
public class PathMatchingResourcePatternResolver{
private final ResourceLoader resourceLoader;
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
}
}
根据代码,最后发现,FileSystemXmlApplicationContext实例将自己包装成PathMatchingResourcePatternResolver并且注入到AbstractApplicationContext中去。这里为什么FileSystemXmlApplicationContext实例可以包装成路径匹配资源解析器呢?因为AbstractApplicationContext本身是FileSystemXmlApplicationContext的父类,同时AbstractApplicationContext也是ResourceLoader的子类。其实说白了就是,基本的功能都是在AbstractApplicationContext中实现的,而FileSystemXmlApplicationContext实例将自己包装成资"源路径匹配资源解析器"最后又注入到AbstractApplicationContext中去。这么做的好处是,当FileSystemXmlApplicationContext改变了某些逻辑的时候,代码可以不用做任何调整。
其次是setConfigLocations(configLocations),这段代码便是将解析后的路径,注入到AbstractRefreshableConfigApplicationContext的成员变量configLocations中去。
最后讲解的是核心refresh(),篇幅有点长,放下一篇吧。
网友评论