Spring IoC容器以及Bean的创建过程
Posted 恒哥的爸爸
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring IoC容器以及Bean的创建过程相关的知识,希望对你有一定的参考价值。
1 Spring 静态结构介绍
什么是Spring,可以自己网上查询,总之,可以说是一个面向Web应用开发的,轻量级,企业级框架。它包含了如下图所示一些模块,这些模块的详细的概念和所负责的职责,可以通过搜索检索到。
1.1 BeanFactory
上图1所示位置, BeanFactory是整个BeanFactoryl类体系中最顶层的接口。
上图2所示, HierachicalBeanFactory 描述了BeanFactory是可以组成一个链表结构。使用名字等信息去查找Bean的时候,当子级BeanFactory内没有找到相应的Bean,可以去父级BeanFactory内去查找。这样可以节省框架内Bean占用的内存。
上图3所示, ListableBeanFactory 是存放Bean的列表接口,可以直接将所有的Bean枚举出来,而不是通过BeanFactory接口中,通过名字等信息来查询Bean。
上图6所示, DefaultListableBeanFactory 实现了BeanDefinitionRegister接口;在DefaultListableBeanFactory中,首先可以看到保存beanDefinition名字和对象映射beanDefinitionMap的一个Map中;另外,所有beanDefinition的名字保存到一个列表中beanDefinitionNames
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
/** List of bean definition names, in registration order */
private final List<String> beanDefinitionNames = new ArrayList<String>(64);
另外,BeanDefinition是用来描述Bean的元信息的类,内部包含了Bean是否有Singleton,Lazyinit,Depends on属性, Dependency check等特性。BeanDefinition可以通过继承于BeanFactoryPostProcessor的接口的类中来修改。
上图4所示, DefaultSingletonBeanRegistry 用于注册,获得,管理singleton对象。
1.2 ApplicationContext
AbstractApplicationContext从上图可以看出,是整个继承体系中,第一个类(抽象类),是整个容器的核心处理类,此类内部有模板函数fresh(模板设计模式),在此函数内,约定容器启动的步骤。子类们可以实现具体特化的启动步骤。另外,注意, 在此类中,有抽象函数getBeanFactory函数,用来获取真正的BeanFactory实例。而AbstractApplicationContext也继承了BeanFactory的接口,而AbstractApplicationContext实现BeanFactory的接口是通过代理getBeanFactory获取的工厂实例实现的,是一个标准的代理设计模式。
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
ClassPathXmlApplicationContext生成的beanFactory的实例,是DefaultListableBeanFactory的对象。此实例,保存在AbstractRefreshableApplicationContext类中。
AbstractApplicationContext中的BeanFactory接口的代理设计模式的实现实例如下,
后续我们在研究整个容器创建过程也是通过refresh这个函数为主线,进行展开的。
2 Spring动态创建简介
2.1 Spring中的多级容器概念
在第一小节中,介绍了HierachicalBeanFactory 接口,说明Spring的容器可以是一个级链为一个列表,并且子容器可以复用父级容器内的Bean;
接下来,我们查看Web.xml文件;一般来说,一共生成了两个容器,一个是ROOT_WEB_APPLICATION_CONTEXT容器,另一个容器是SpringMVC容器,SpringMVC容器的父容器是ROOT_WEB_APPLICATION_CONTEXT容器。
ROOT_WEB_APPLICATION_CONTEXT根容器是通过ContextLoaderListener类生成的,这个类的调用时因为继承了ServletContextListener接口的,所以,ContextLoaderListener会在创建完ServletContext后,进行调用,这个时刻,所有的Servlet还未创建。因为,要在这个地方来初始化Servlet公用的一些对象,例如数据库相关的对象,以备后续的Servlet来调用。
<!--第一个容器: Spring上下文监听器配置,生成根容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--DispatcherServlet MVC容器 -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:context-dispatcher.xml</param-value>
</init-param>
</servlet>
我们查看ContextLoadListener调用栈,能明显的看到ROOT_WEB_APPLICATION_CONTEXT容器的创建调用栈。
2.2 Spring根容器创建的过程
Spring Ioc容器创建的过程,如果直接去跟踪代码的话,是一个非常复杂的过程,很容易陷入进去。下图也是从另外一个博客中直接拷贝的,现在也忘记链接了,希望作者不要介意。从下图,能很明白的看出,重要分为以下4步的执行,完成容器的创建。
1 创建BeanFactory,之后,将BeanDefinition注册到BeanFactory的实例中,最后将这些信息保存在上文描述的beanDefinitionMap中,并且将名字也保存到beanDefinitionNames的数组中。这里要说明的是,Spring中的Bean的创建信息,是以BeanDefinition类来描述的。内部描述当前Bean是否是单例Bean,是否延时初始化,依赖属性,依赖值类型检测等属性。
2 对第一步创建的BeanDefinition进行修改;继承于BeanFactoryPostProcessor接口的类,实例化后,要对第一步生成的BeanDefinition实例的属性进行修改。在下图中的第二部invokeBeanFactoryPostProcessors函数中,调用这些接口,用来修改BeanDefinition的 某些特性;
3 实例化并注册继承于BeanPostProcessor接口的类;在registerBeanPostProcessors的函数中,会实例化Bean的后处理器。这些后处理器,是继承于BeanPostProcessor接口的子类,是针对初始化完毕的Bean实例进行一些属性的修改(这里要注意,继承于BeanFactoryPostProcessor的类是用来修改BeanDefinition的属性,而继承于BeanPostProcessor的类是用来修改Bean的。这两类接口统称为PostProcessor后处理,主要是为了统一修改BeanDefinition和Bean的)。这些需要修改的Bean,通常是通过通过注释或者接口,来标记这些需要修改的Bean。Spring中,一个非常重要的应用AOP,就是在靠这些继承于BeanPostProcessor接口的类来进行处理的。
4 创建Bean
在finishBeanFactoryInitialization函数中,初始化Bean。从以下代码中,能看出,容器的初始化过程refresh函数内,函数的调用过程。
2.3 Bean初始化过程
此章节,将概要的介绍2.2中第四步的初始Bean流程。所以,可见Bean和new出来的实例对象,完全不是一个概念。Bean生成的过程更复杂,只有完成了所有的初始化过程,才是合格的SpringBean。
1 循环在之前步骤中生成的beanDefinitionNames数组;
2 查看每个BeanDefinition,是否有依赖属性需要实例化,需要的话,先实例所有需要实例化的依赖属性
3 利用反射原理,实例化Bean实例
4 将依赖属性注入到Bean中;
5 执行初始化过程,内部会调用后处理器(继承于BeanPostProcessor的类),以及一些初始化接口
接下来将通过代码,概要介绍下,Bean的生成过程;由于DefaultListableFactory实例保存了BeanDefinition的对象Map,和名字数组beanDefinitionNames,所有,首先就是循环这个beanDefinitionNames列表,在循环体内,会调用getBean来尝试的获取Bean。
public void preInstantiateSingletons() throws BeansException {
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { //初始化非延时加载的单例Bean
... ...省略
getBean(beanName);
}
}
}
进入getBean函数,可以看到,程序会最终调用到AbstractBeanFactory中的doGetBean函数中。我们只看主流程,获取名字对应的BeanDefinition对象,检查是否有依赖属性,如果有,就循环创建依赖属性的Bean,然后,通过createBean来创建Bean。
//AbstractBeanFactory
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
... ... 省略
final String beanName = transformedBeanName(name);
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 是否有依赖属性,如果有,循环创建依赖属性的Bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
registerDependentBean(dependsOnBean, beanName);
getBean(dependsOnBean);
}
}
// 创建Bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return createBean(beanName, mbd, args);
}
});
}
... ...省略
}
继续查看 createBean的源代码,最后能看到最终调用的是doCreateBean函数,在此函数中,首先通过调用createBeanInstance来实例化Bean;感兴趣可以自己去查看细节,主要还是通过反射原理来实例化类,具体的实例化细节,不会影响对整个过程的理解。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
//... ... 省略
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Initialize the bean instance.
Object exposedObject = bean;
//填充依赖属性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// ... ... 省略
return exposedObject;
}
//AbstractAutowareCapableBeanFactory
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
//... ...省略
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//PostProcessor的后处理器的postProcessBeforeInitialization接口函数调用
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//... ...省略
//如果当前Bean实现了InitializingBean接口,那么afterPropertiesSet函数将会被调用
invokeInitMethods(beanName, wrappedBean, mbd);
//... ...省略
if (mbd == null || !mbd.isSynthetic()) {
//PostProcessor的后处理器的postProcessAfterInitialization接口函数调用
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
这里要注意,PostProcessor也可以理解为,是Spring框架给了我们一个可以对Bean做一切处理一个机会。例如,ApplicationContextAwareProcessor这个后处理器,这个处理器是内置的后处理器。但是,这个类是为了当前Bean如果实现了某些特定的接口,那么这个后处理,可以去调用这些接口方法,来初始化当前Bean。例如,ApplicationContextAware接口,可以使我们获取ApplicationContext容器对象,具体见如下代码。至此,一个合格的Bean就创建完毕。
class ApplicationContextAwareProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
//省略
invokeAwareInterfaces(bean);
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
// 如果当前Bean实现了此接口,将会被调用
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
}
以上是关于Spring IoC容器以及Bean的创建过程的主要内容,如果未能解决你的问题,请参考以下文章
Spring IOC 容器源码分析 - 创建单例 bean 的过程