Spring IOC源码分析
1、建立一个上下文-------ApplicationContext 一般是这两种
//ClassPathXmlApplicationContext默认从classpath下查找xml文件,也就是打包了的项目路径
//FileSystemXmlApplicationContext在指定的文件系统路径下查找xml文件
ApplicationContext context = new ClassPathXmlApplicationContext();
ApplicationContext context1 = new FileSystemXmlApplicationContext();
然后从容器中获取bean也就是 context.getBean();
异曲同工,功能几乎都差不多,所以本文从ClassPathXmlApplicationContext入手
2、ClassPathXmlApplicationContext源码,乍一看吓一跳,仔细看看,都基本上是构造方法,肯定会有人对于configResources的作用有疑问,这里我在比较了FileSystemXmlApplicationContext的源码后,本人推测应当是整个项目的配置信息,应该就是传递资源绝对路径给这个类。
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
@Nullable//表示这个字段可以为空
private Resource[] configResources;
public ClassPathXmlApplicationContext() {
}
public ClassPathXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] configLocations, @Nullable ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}
public ClassPathXmlApplicationContext(String path, Class<?> clazz) throws BeansException {
this(new String[]{path}, clazz);
}
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz) throws BeansException {
this(paths, clazz, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for(int i = 0; i < paths.length; ++i) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
this.refresh();
}
@Nullable
protected Resource[] getConfigResources() {
return this.configResources;
}
}
而上面这么多构造方法其实最终可能执行的就这三个
1、父类的带parent的参数的方法
AbstractXmlApplicationContext->.......->最终执行的便是AbstractApplicationContext的无参构造方法和setParent()方法
AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();//调用无参构造方法
this.setParent(parent);//设置parent属性为空则不合并环境信息
}
public AbstractApplicationContext() {
this.logger = LogFactory.getLog(this.getClass());//获取日志
this.id = ObjectUtils.identityToString(this);
this.displayName = ObjectUtils.identityToString(this);
this.beanFactoryPostProcessors = new ArrayList();//beanpostprocessor这个东西是bean生命周期的一个接口
this.active = new AtomicBoolean();
this.closed = new AtomicBoolean();
this.startupShutdownMonitor = new Object();//这个做的是一个syn的锁
this.applicationListeners = new LinkedHashSet();//监听器
this.resourcePatternResolver = this.getResourcePatternResolver();
}
public void setParent(@Nullable ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
}
}
}
2、configLocations 配置信息 refresh 是否刷新工厂,也就是重新弄个beanFactory对象 parent一个可谓为空的 ApplicationContext 对象
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}
3、paths 路径信息 clazz 传递了这个这个类编译过后的信息 parent 同上
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for(int i = 0; i < paths.length; ++i) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
this.refresh();
}
3、!!!不难发现,这些构造方法都调用了一个关键性的refresh()方法的调用,这个就是重点了。
(1)BeanPostProcessor 与 postProcessBeanFactory:
两者都是IOC特意留下来为了拓展功能而做的,但是BeanPostProcessor是在bean的创建之前或者之后执行一些开发着想要执行的功能,可以定义多个BeanPostProcessor,并根据order建立优先级(0为最高);而postProcessBeanFactory则是通过beanfactory可以获取到bean的定义信息,并且可以修改
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
//为刷新做准备工作,如日志,将原本的内容存储到一个hashset里面
this.prepareRefresh();
//刷新beanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//顾名思义,进行准备创建前的准备工作,
//如各种依赖,添加BeanPostProcessor(通过order设置优先级0为最高)这种拓展IOC功能的方法,获取类加载器等等
this.prepareBeanFactory(beanFactory);
try {
//这里有一个postProcessBeanFactory与上面的BeanPostProcessor略有不同
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
4、再好好看看ClassPathXmlApplicationContext 的生成树
这个就你们自己去找了,这图可能不清晰
5、spring bean的生命周期