Spring IOC容器初始化过程 源码分析
本文主要记录Spring容器创建 源码分析过程。
本文主要记录Spring容器创建 源码分析过程。
首先贴上一张时序图,好久没画,忘的差不多了,画的不好,可以凑合看一下。
接下来,贴上一份测试代码,这里使用AnnotationConfigApplicationContext来初始化Spring容器
@Test
public void test1() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("spring容器初始化结束");
Person person = (Person) ctx.getBean("person");
System.out.println(person.toString());
}
@Configuration
public class AppConfig {
@Bean(value="person")
public Person getPerson() {
Person person = new Person();
person.setName("zhangsan");
return person;
}
}
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
代码看完了,直接进入正题,开始Debug。
Debug从AnnotationConfigApplicationContext的构造器方法开始,找到该构造方法。
往下继续走,进入到AbstractApplicationContext的refresh()方法,Spring容器的初始化过程就在该方法中完成的。
本文会进入每个方法,看看方法里面的代码,但可能不会很细。
1、接下来,继续Debug,进入第一个方法prepareRefresh(),该方法主要是进行刷新前的预处理操作。
2、进入第二个方法ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(),该方法主要是获取beanFactory。
进入refreshBeanFactory(),会跳到GenericApplicationContext的refreshBeanFactory()方法。这里讲一下
GenericApplicationContext有个构造方法,会new一个新的DefaultListableBeanFactory。
而进入refreshBeanFactory()先当于new一个DefaultListableBeanFactory,并设置一个序列化值。
返回接在再看getBeanFactory()方法,跳到GenericApplicationContext的getBeanFactory(),返回上一步创建的DefaultListableBeanFactory
最后将该beanFactory(DefaultListableBeanFactory)返回。
3、接着进入第三个方法prepareBeanFactory(beanFactory),该方法主要是beanFactory的预准备工作,也就是对beanFactory进行一些初始化后的设置;
1)、设置BeanFactory的类加载器、支持表达式解析器…
2)、添加部分BeanPostProcessor(ApplicationContextAwareProcessor)
3)、设置忽略的自动装配的接口EnvironmentAware、EmbeddedValueResolverAware等;
4)、注册可以解析的自动装配,我们能直接在任何组件中自动注入:
BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
5)、添加BeanPostProcessor【ApplicationListenerDetector】
6)、添加编译时的AspectJ;
7)、往BeanFactory中注册组件;environment、 systemProperties、systemEnvironment。
4、接着往下走,进入第4个方法postProcessBeanFactory(beanFactory),发现该方法是交给子类重写的,子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}
--------------------------------以上是BeanFactory的创建及预准备工作-----------------------------
5、继续进入第5个方法invokeBeanFactoryPostProcessors(beanFactory),该方法主要是调用beanFactory的后置处理器,在BeanFactory标准初始化之后执行的。这里我们主要跟踪一下AppConfig.class中person bean的生成。看下图,继续进入跟踪
在processConfigBeanDefinitions(BeanDefinitionRegistry registry)中找到下图代码,该代码就是加载person bean定义的。往后就不继续了。
执行完这句代码,可以看一下beanFactory中的beanDefinitionMap属性,已经多了一个person bean 定义
考虑到篇幅,以下几个步骤就不展示代码,只说一下方法里面的操作。
6、registerBeanPostProcessors(beanFactory)。该方法主要往beanFactory注册Bean的后置处理器。
不同接口类型的BeanPostProcessor,在Bean创建前后的执行时机是不一样的。有以下几个步骤:
一、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
二、先注册PriorityOrdered优先级接口的BeanPostProcessor;
把每一个BeanPostProcessor;添加到BeanFactory中
beanFactory.addBeanPostProcessor(postProcessor);
三、再注册Ordered接口的
四、 最后注册没有实现任何优先级接口的
五、最终注册MergedBeanDefinitionPostProcessor;
六、注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是
applicationContext.addApplicationListener((ApplicationListener<?>) bean);
7、initMessageSource()。该方法主要初始化MessageSource组件(国际化功能;消息绑定,消息解析)。有以下几个步骤:
一、 获取BeanFactory
二、看容器中是否有id为messageSource的,类型是MessageSource的组件
如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;
MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
三、 把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale);
8、initApplicationEventMulticaster();该方法主要初始化事件派发器;有以下几个步骤:
一、获取BeanFactory
二、 从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
三、如果上一步没有配置;创建一个SimpleApplicationEventMulticaster
四、 将创建的ApplicationEventMulticaster添加到BeanFactory中,以后其他组件直接自动注入
9、onRefresh();该方法主要在容器刷新的时候可以自定义逻辑,留给子类实现。
10、registerListeners();该方法主要在容器中将所有项目里面的ApplicationListener注册进来。有以下几个步骤:
一、从容器中拿到所有的ApplicationListener
二、 将每个监听器添加到事件派发器中;
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
三、派发之前步骤产生的事件;
11 、接下来重点看一下这个方法finishBeanFactoryInitialization(beanFactory);该方法作用是实例化所有剩下的懒加载单实例。
重点看一下下面这段代码
@Override
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 获取容器中的所有Bean定义名字
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
1.先获取bean定义
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
2.判断Bean是不是抽象的,是不是单实例的,是不是懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
判断是否是FactoryBean;
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
是否是实现FactoryBean接口的Bean
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
//我们重点看一下这个方法。不是工厂bean,通过该方法获取创建bean实例
getBean(beanName);
}
}
}
xxxxxx
当循环的beanName 为person的时候,我们debug进这个getBean(beanName)方法。
继续debug,进入方法。因为person实例还没有创建,beanFactory中的singletonObjects肯定找不到。一些判断这里就不展示,直接跳过了。找到下面代码
继续debug,进入createBean(beanName, mbd, args);
找到下面代码,进入doCreateBean(beanName, mbdToUse, args);
debug了半天,终于要创建bean实例了。这里Spring容器使用BeanWrappe。BeanWrapper是对Bean的包装,大部分情况下是在spring ioc内部进行使用,用来设置获取被包装的bean对象,获取被包装bean的属性描述器等。
Debug进入createBeanInstance(beanName, mbd, args);
进入debug,进入。通过工厂方法来实例化
继续进入,找到下面代码。beanFactory通过实例化策略来实例化bean
继续debug,进入。找到图中的代码,箭头标记的方法,就是最后生成bean的方法,通过工作方法调用生成实例bean。
执行完上图箭头代码factoryMethod.invoke(factoryBean, args),bean实例已经生成了,控制台会打印下面这句话。
一路返回,返回到
AbstractAutowireCapableBeanFactory的 doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)方法。想方便点的话,断点直接打到箭头标记的那行,就不需要一路return回去了。这时候可以看到实例bean的信息。
往下继续走,找到下图的代码,箭头中的方法是对实例bean进行赋值。里面有赋值之前的一些后置处理器的处理和利用setter方法等为属性进行赋值操作。这里简单介绍下。
往下看到initializeBean(beanName, exposedObject, mbd)方法。在该方法中进行bean的初始化。里面也是一些后置处理器的操作。
然后,继续返回出去,来到AbstractBeanFactory的doGetBean方法。
这个方法上面见过了,之前只对图中的createBean(beanName, mbd, args)进行分析。现在我们看一下getSingleton(…)这个方法。这个方法也简单,就是从beanFactory的singletonObjects(Map)属性中获取该beanName的值,如果存在,则返回;否则,将该beanName和对应的bean实例添加到singletonObjects属性中。
12、最后看一下refresh() 方法里面的最后一个方法finishRefresh()。该方法主要完成BeanFactory的初始化创建工作。这样IOC容器就创建完成了。
经过上面n多步骤,spring ioc容器初始化过程就结束了
Person person = (Person) ctx.getBean("person");
接下来这个获取person bean就简单了。它的原理就是从beanFactory的singletonObjects(map)中,通过key,获取value了。源码上面也看过了。
学习源码的过程是枯燥的,由于是全英文,可能看着也比较累,但是学习完,感觉收获还是颇多了。由于这个初始化过程步骤比较多,涉及到的东西也比较多,这里看一下,那里看一下,多个类之间切来切去,可能看着也会比较乱一点。但是多看几遍,相信大家也会对这个过程比较了解了。
个人总结:从上面几个步骤可以看出,IOC容器初始化的过程,大部分都是往ioc容器的诸多Map中添加值,方便后续读取使用。读取的时候只需要从Map中根据key取值就可以了。
到此,本篇文章也就结束了。该篇文章主要是记录本人学习spring ioc容器源码的一个过程。中间可能存在一些问题,或有一些不够严谨完善的地方,希望大家体谅体谅。有问题的话,欢迎大家留意,交流交流。
更多推荐
所有评论(0)