Spring框架是我接触的第一个框架,那时候觉得像天书一样复杂,但因为java开发者很多,所以相关的Spring 框架解析视频,博客是非常多的,而且讲得细致又清晰。而到面试的时候,Spring 也几乎是基础必问的题目,很多时候我有印象,但脑海中又没有很清晰的概念,所以我得再学习一遍,并用博客的形式做个记录。
很多时候,理解一个框架得知道这个框架是做什么的,它解决了什么问题,然后会用,再跟踪代码debug一下它的内部执行流程,知道它怎么做,跳出来,然后才知道它是通过什么样的方式解决一个问题的。当然,Spring 框架的代码量很大,我们只需要知道它的重要步骤和关键节点就可以了。但像Spring 事务这种代码量不算大的框架,应该会有人手写一个事务管理器的。
Spring 框架主要解决Bean的自动生成和Bean的注入和依赖问题,因为Spring有一个装满了Bean的Ioc容器,在这个容器里的所有Bean都是由Ioc容器所管理的,这些Bean的内部依赖也被Ioc容器所解决了。所以Spring有两个问题要解决:1是容器初始化,因为容器是管理Bean的生命周期的,是为Bean服务的,所以容器初始化的一切步骤都是为了创建Bean的环境而服务,包括解析bean标签创建BeanDefinition,BeanDefinition是Bean实例化和初始化的基础;创建BeanFactoryPostProcessor类,这个类可以修改BeanDefinition的信息;注册BeanPostProcessor,它可以拦截所有Bean的创建和初始化,给所有Bean添加一些统一的东西;还有一些MessageSource支持国际化,事件广播机制的初始化,但我们用得很少,不是主要的内容。 2是Bean的装配,Bean会在BeanDefinition的基础上通过new 或反射的方式创建出来,并解决Bean内部引用的依赖注入问题,然后被BeanPostProcessor所拦截并进一步初始化,添加一些信息,在这个过程中,Bean会通过三级缓存的方式解决循环依赖的问题,如果要生成Bean的代理,会涉及到Spring Aop。在Bean装配的过程中,还有InitialingBean这种接口的afterPropertiesSet()这种初始化的钩子方法,还有bean标签的init-method 属性的钩子方法,在容器完全初始化完后还有@PostConstruct这样的钩子方法。
所以我们很明显地看到Spring 框架就做了这两件事,这两件事是有联系的,Spring只想做第二件事,但做第二件事前得先做第一件事,先创建Ioc容器,再往Ioc里填充Bean,后面我们只需要往Ioc容器里拿Bean来用就可以了。
首先我们先写一个demo。
public void testApp() {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
TestService testService = (TestService) context.getBean("testService");
String result = testService.hello("world");
System.out.println(result);
}
new ClassPathXmlApplicationContext()会创建Ioc容器并完成Bean的装配,如果这个过程中出现了问题,就启动失败,直接报错。后面我3句代码是检查这个容器里是否有名称为testService的Bean对象,有就取出来,执行它的一个方法。
查看ClassPathXmlApplicationContext类及其父类,父类的父类,没多久就看到了 AbstractApplicationContext#refresh()方法。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
...
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
这里使用了模板模式来完成初始化,如果是web 项目,还会初始化web子容器。 网上找的图:
每一个方法都会做很多事情。
未完待续。。。