Spring IOC-源码解读BeanFatory与ApplicationContext-第二篇

接上一篇文章,上一篇重点讲了Spring ioc容器的核心类和整体的体系架构。ioc容器内其实有两大设计主线,一个是BeanFactory一个是ApplicationContext。本章,重点对这两大设计主线进行一探究竟,主要从以下维度出发:

  • BeanFactory与ApplicationContext的应用场景,以及实现原理(只涉及容器的初始化过程,暂不考虑Bean)。

BeanFactory

应用场景

beanFactory提供了最基本的IOC容器的能力。是Spring ioc工厂的顶层规范,定义了很多核心方法。例如:

  1. getBean, 从工厂中获取一个Bean。
  2. containsBean,容器内是否包含指定名字的Bean。
  3. isSingleton,查询指定名字的Bean是否是单例类型。
  4. ......

类图结构,这里以具体的实现类xmlbeanFactory为例:

相关核心类,简单剖析:

XmlBeanFactory:继承自defaultListableBeanFactory,构造方法支持传入外部的Resource资源,同时持有org.springframework.beans.factory.xml.XmlBeanDefinitionReader这个类,可以直接调用此类,将xml文件转换为Spring内部的数据结构BeanDefinition,最终注册到BeandefinitionRegistry内

DefaultListableBeanFactory: beanFactory的始祖,spring ioc内部非常核心的一个类,里面实现了大部分beanFactory接口的方法,此类既可以作为一个单独的beanFactory,也可以作为自定义beanFactory的父类。

AbstractAutowireCapableBeanFactory:实现了org.springframework.beans.factory.config.AutowireCapableBeanFactory这个接口,重点是实现了AbstractBeanFactory这个类的createBean方法。提供对Bean创建的支持,属性填充,自动装配和初始化等能力,同时能够处理运行时Bean的音容,解析托管集合,调用初始化方法等。

FactoryBeanRegistrySupport:支持需要处理的,由FactoryBean生成的单例注册的基类。继承DefaultSingletonBeanRegistry类。后面会说一下FactoryBean与BeanFactory的区别。

BeanDefinitionRegistry:beanDefinition注册管理接口,负责对BeanDefinition进行注册,删除,获取等逻辑

初始化核心流程

public class XmlBeanFactoryTest {

    public static void main(String[] args) {
        XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("spring-ioc-test1.xml"));
        Object bean = xmlBeanFactory.getBean("asdThreadPool");
        System.out.println("====Bean====" + bean);
    }

}

整体流程:

1)XmlBeanFactory 执行构造方法,因为持有XmlBeanDefinitionReader类,会负责对xml文件进行读取。loadBeanDefinitions会负责把Resource对应的实现类ClassPathResource,读进内存,转换为Document对象。

2)DefaultBeanDefinitionDocumentReader#registerBeanDefinitions,负责把Document对象,转化为Element对象,并对每个Node进行解析。

3)DefaultBeanDefinitionDocumentReader#processBeanDefinition,负责把Element对象转换为BeanDefinitionHolder。

4) BeanDefinitionReaderUtils#registerBeanDefinition,负责把BeanDefinitionHolder注册到Registry内。

5)真正的注册方法:DefaultListableBeanFactory#registerBeanDefinition,把BeanDefinition注册进入beanDefinitionMap内。

能力梳理

BeanFactory作为最上层的接口,提供了一些最基本的能力,如下:

  1. 根据bean的名称获取实例bean对象。
  2. 根据bean的名称和class类型获取实例bean对象。
  3. 是否包含bean.
  4. 是否是单例bean。
  5. 是否是原型bean。
  6. 是否匹配,根据name和class类型去匹配。

ApplicationContext

应用场景

ApplicationContext为Spring ioc提供一些高阶功能,是Spring中的中心接口,提供了一系列可配置的能力,在beanFactory基础之上多了如下功能:

  1. 以通用方式加载资源文件的能力。继承了ResourceLoader接口。
  2. 发布注册事件的能力。继承了ApplicationEventPublisher接口。
  3. 解析资源文件的能力,可以通过资源文件支持国际化。继承了MessageSource接口。
  4. 有独立的上下文机制,这种上下文可以从父类的上下文继承,但是彼此之间是互相隔离的。(这个特性在我司的dubbo富客户端开发中使用较多,例如:Redis缓存是一个单独的上下文,Memcache缓存是一个单独的上下文,最后可以统一加到父的上下文中,子上下文之间彼此是互相独立的,不影响。)

类图结构

相关核心类,简单剖析

EnvironmentCapable:ApplicationContext接口继承此接口,此接口代表,环境能力接口,此接口代表要指定具体关联的环境。

MessageSource:消息接口,提供对国际化的支持。

ApplicationEventPublisher:发布事件接口,可以发布一个ApplicationEvent类型的事件,也可以发布一个Object类型的事件。

ListableBeanFactory:拓展了BeanFactory接口,同时继承于BeanFactory,可以列举出所有的Bean。例如,通过名称获取bean的列表,通过类型获取bean的列表,通过注解获取bean的列表,获取bean的总个数。

HierarchicalBeanFactory:分层的beanFactory,继承自BeanFactory,内只有两个方法,1)用来获取父的BeanFactory。2)用来判断工厂内是否包含某个Bean。

Lifecycle:生命周期接口,包含开始,停止,是否正在运行三个生命周期阶段的接口。

ResourceLoader:资源load接口,提供了获取Resource的方法,传入一个指定位置,可获取资源。

初始化核心流程

实例代码:

public class ClassPathXmlApplicationContextTest {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext pathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-ioc-test1.xml");
        System.out.println("=======ClassPathXmlApplicationContext=========" + pathXmlApplicationContext);
        AsdThreadPool asdThreadPool = pathXmlApplicationContext.getBean("asdThreadPool", AsdThreadPool.class);
        System.out.println("============asdThreadPool=========" + asdThreadPool);
    }

}

AbstractApplicationContext类的refresh方法核心代码

@Override
	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) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

1.prepareRefresh(); 将active的状态改为True,验证配置文件是否合法。

2.obtainFreshBeanFactory(): 这一块对应的操作比较多,首先会生成DefaultListableBeanFactory对象,其次会对beanFactory进行一些个性化的设置,最后一步是最复杂的,是将xml中定义的bean转换为spring ioc内部的BeanDefinition,最后将BeanDefinition注册到Registry,这段的逻辑和代码,是复用上文BeanFactory注册的逻辑代码。

3.prepareBeanFactory(beanFactory);配置beanFactory,例如设置BeanPostProcesser,BeanClassLoader等。

4.postProcessBeanFactory(beanFactory);留给开发者的一个拓展接口,在此时可以修改BeanFactory内的配置,或者修改BeanDefinition,因为此时工厂内只有BeanDefinition,未有真正的Bean实例。

5.invokeBeanFactoryPostProcessors(beanFactory);实例化并且调用所有注册到上下文中的BeanFactoryPostProcessor。BeanFactoryPostProcessor是Spring的一个拓展点,很多应用都会利用这个拓展点去做一些前置的事情。例如:disconf-client的DisconfMgrBean实现了BeanFactoryPostProcessor的子类BeanDefinitionRegistryPostProcessor,在spring ioc 容器调用invokeBeanFactoryPostProcessors此方法时,postProcessBeanDefinitionRegistry会被触发,此时可以拿到BeanDefinitionRegistry可以对bean做一些个性化的操作。

6.registerBeanPostProcessors(beanFactory);注册beanPostProcessor到工厂内。BeanPostProcessor也是Spring内常用的一个拓展点,可以拿到指定的Bean,在bean初始化之前Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;和bean初始化之后Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;加入自己的逻辑。

7.initMessageSource,初始化所有实现了MessageSource的接口,主要提供对国际化的支持。

8.initApplicationEventMulticaster(); 初始化所有实现ApplicationEventMulticaster接口的类,主要是对多个对象的事件ApplicationEvent进行广播。

9.onRefresh,拓展点,在子bean工厂内初始化其他的指定的一些bean。

10.registerListeners,注册applicationEvent的监听器。

11.finishBeanFactoryInitialization(beanFactory);初始化所有剩余的单例类(非惰性初始化的类)。 default-lazy-init="false"即非惰性初始化,这样的话,bean在spring ioc容器启动过程中,单例的bean就被初始化了。如果default-lazy-init="true",则会在getBean这个操作,才会将bean进行初始化。大多数情况,为了减少请求的rt,最好是在系统启动时将bean都已经实例化好。

12.finishRefresh(); 1)初始化上下文中所有实现了LifeCycleProcessor接口的类。2)执行所有实现了LifecycleProcessor接口的onRefresh方法。3)发布ContextRefreshedEvent事件。4)把spring内所有存活的bean,通过mbean的方式暴露出来,即提供了一个对所有存活bean的监控。这个有点意思。

总结

  • beanFactory的初始化相对而言比较简单,主要是对Resource资源解析为BeanDefinition,同时注册到Registry内。BeanFactory作为Spring ioc容器的顶层接口,提供了一些最基本通用的能力。
  • ApplicationContext的初始化非常复杂,refresh方法内每个初始化的方法,逻辑深入一看都比较复杂,这里只是提炼了一些最基本的。ApplicationContext的启动过程中,提供了很多拓展点。spring的拓展点实在是太好用了,设计真的是太精妙了。spring的拓展点具体是如何与启动过程结合起来的,这块还需要具体去分析。

下章预览

  • FactoryBean与BeanFactory的区别?
  • Spring内一些常见的拓展点,以及如何使用,对应的案例?
  • Spring内拓展点是如何与ioc的启动过程结合到一起的?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值