9. Bean对象作用域以及FactoryBean的实现和使用
9. Bean对象作用域以及FactoryBean的实现和使用
工程结构
lqf-spring-step-09
├── main
│ ├── java
│ │ └── lqf
│ │ └── springframework
│ │ ├── beans
│ │ │ ├── BeansException.java
│ │ │ ├── PropertyValue.java
│ │ │ ├── PropertyValues.java
│ │ │ └── factory
│ │ │ ├── Aware.java
│ │ │ ├── BeanClassLoaderAware.java
│ │ │ ├── BeanFactory.java
│ │ │ ├── BeanFactoryAware.java
│ │ │ ├── BeanNameAware.java
│ │ │ ├── ConfigurableListableBeanFactory.java
│ │ │ ├── DisposableBean.java
│ │ │ ├── FactoryBean.java
│ │ │ ├── HierarchicalBeanFactory.java
│ │ │ ├── InitializingBean.java
│ │ │ ├── ListableBeanFactory.java
│ │ │ ├── config
│ │ │ │ ├── AutowireCapableBeanFactory.java
│ │ │ │ ├── BeanDefinition.java
│ │ │ │ ├── BeanFactoryPostProcessor.java
│ │ │ │ ├── BeanPostProcessor.java
│ │ │ │ ├── BeanReference.java
│ │ │ │ ├── ConfigurableBeanFactory.java
│ │ │ │ └── SingletonBeanRegistry.java
│ │ │ ├── support
│ │ │ │ ├── AbstractAutowireCapableBeanFactory.java
│ │ │ │ ├── AbstractBeanDefinitionReader.java
│ │ │ │ ├── AbstractBeanFactory.java
│ │ │ │ ├── BeanDefinitionReader.java
│ │ │ │ ├── BeanDefinitionRegistry.java
│ │ │ │ ├── CglibSubclassingInstantiationStrategy.java
│ │ │ │ ├── DefaultListableBeanFactory.java
│ │ │ │ ├── DefaultSingletonBeanRegistry.java
│ │ │ │ ├── DisposableBeanAdapter.java
│ │ │ │ ├── FactoryBeanRegistrySupport.java
│ │ │ │ ├── InstantiationStrategy.java
│ │ │ │ └── SimpleInstantiationStrategy.java
│ │ │ └── xml
│ │ │ └── XmlBeanDefinitionReader.java
│ │ ├── context
│ │ │ ├── ApplicationContext.java
│ │ │ ├── ApplicationContextAware.java
│ │ │ ├── ConfigurableApplicationContext.java
│ │ │ └── support
│ │ │ ├── AbstractApplicationContext.java
│ │ │ ├── AbstractRefreshableApplicationContext.java
│ │ │ ├── AbstractXmlApplicationContext.java
│ │ │ ├── ApplicationContextAwareProcessor.java
│ │ │ └── ClassPathXmlApplicationContext.java
│ │ ├── core
│ │ │ └── io
│ │ │ ├── ClassPathResource.java
│ │ │ ├── DefaultResourceLoader.java
│ │ │ ├── FileSystemResource.java
│ │ │ ├── Resource.java
│ │ │ ├── ResourceLoader.java
│ │ │ └── UrlResource.java
│ │ └── util
│ │ └── ClassUtils.java
│ └── resources
└── test
├── java
│ └── lqf
│ └── springframework
│ ├── IUserDao.java
│ ├── ProxyBeanFactory.java
│ ├── SpringTest.java
│ ├── UserDao.java
│ ├── UserService.java
│ └── common
│ ├── MyBeanFactoryPostProcessor.java
│ └── MyBeanPostProcessor.java
└── resources
├── important.properties
├── spring.xml
└── springPostProcessor.xml
Spring 单例、原型以及 FactoryBean 功能实现类关系,如图:

- 以上整个类关系就是关于 Bean 对象作用域以及 FactoryBean 的实现。
- 整个实现的过程并不复杂,只是在现有的 AbstractAutowireCapableBeanFactory 类以及继承的抽象类 AbstractBeanFactory 中进行扩展。
- 不过这次把 AbstractBeanFactory 继承的 DefaultSingletonBeanRegistry 类,中间加了一层 FactoryBeanRegistrySupport,这个类在
Spring 框架中主要是处理关于 FactoryBean 注册的支撑操作。
设计
关于提供一个能让使用者定义复杂的 Bean 对象,功能点非常不错,意义也非常大,因为这样做了之后 Spring
的生态种子孵化箱就此提供了,谁家的框架都可以在此标准上完成自己服务的接入。
但这样的功能逻辑设计上并不复杂,因为整个 Spring
框架在开发的过程中就已经提供了各项扩展能力的接茬,你只需要在合适的位置提供一个接茬的处理接口调用和相应的功能逻辑实现即可,像这里的目标实现就是对外提供一个可以二次从
FactoryBean 的 getObject 方法中获取对象的功能即可,这样所有实现此接口的对象类,就可以扩充自己的对象功能了。整体设计结构如下图:

- 整个的实现过程包括了两部分,一个解决单例还是原型对象,另外一个处理 FactoryBean
类型对象创建过程中关于获取具体调用对象的getObject操作。 SCOPE_SINGLETON、SCOPE_PROTOTYPE,
对象类型的创建获取方式,主要区分在于AbstractAutowireCapableBeanFactory#createBean创建完成对象后是否放入到内存中,如果不放入则每次获取都会重新创建。createBean执行对象创建、属性填充、依赖加载、前置后置处理、初始化等操作后,就要开始做执行判断整个对象是否是一个
FactoryBean
对象,如果是这样的对象,就需要再继续执行获取 FactoryBean 具体对象中的 getObject 对象了。整个getBean
过程中都会新增一个单例类型的判断factory.isSingleton(),用于决定是否使用内存存放对象信息。
实现
Bean的作用范围定义和xml解析
源码1: lqf.springframework.beans.factory.config.BeanDefinition
- singleton、prototype,是本次在 BeanDefinition 类中新增加的两个属性信息,用于把从 spring.xml 中解析到的 Bean 对象作用范围填充到属性中。
源码2: lqf.springframework.beans.factory.xml.XmlBeanDefinitionReader
- 在解析 XML 处理类 XmlBeanDefinitionReader 中,新增加了关于 Bean 对象配置中 scope 的解析,并把这个属性信息填充到 Bean
定义中。beanDefinition.setScope(beanScope)
创建和修改对象时候判断单例和原型模式
源码: lqf.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
- 单例模式和原型模式的区别就在于是否存放到内存中,如果是原型模式那么就不会存放到内存中,每次获取都重新创建对象,另外非
Singleton 类型的 Bean 不需要执行销毁方法。 - 所以这里的代码会有两处修改,一处是 createBean 中判断是否添加到 addSingleton(beanName, bean);,另外一处是
registerDisposableBeanIfNecessary 销毁注册中的判断if (!beanDefinition.isSingleton()) return;。
定义 FactoryBean 接口
源码: lqf.springframework.beans.factory.FactoryBean
- FactoryBean 中需要提供3个方法,获取对象、对象类型,以及是否是单例对象,如果是单例对象依然会被放到内存中。
实现一个 FactoryBean 注册服务
源码: lqf.springframework.beans.factory.support.FactoryBeanRegistrySupport
- FactoryBeanRegistrySupport 类主要处理的就是关于 FactoryBean
此类对象的注册操作,之所以放到这样一个单独的类里,就是希望做到不同领域模块下只负责各自需要完成的功能,避免因为扩展导致类膨胀到难以维护。 - 同样这里也定义了缓存操作 factoryBeanObjectCache,用于存放单例类型的对象,避免重复创建。
- doGetObjectFromFactoryBean 是具体的获取 FactoryBean#getObject() 方法,因为既有缓存的处理也有对象的获取,所以额外提供了
getObjectFromFactoryBean 进行逻辑包装,这部分的操作方式是不和你日常做的业务逻辑开发非常相似。
扩展 AbstractBeanFactory 创建对象逻辑
源码: lqf.springframework.beans.factory.support.AbstractBeanFactory
- 首先这里把 AbstractBeanFactory 原来继承的 DefaultSingletonBeanRegistry,修改为继承 FactoryBeanRegistrySupport。因为需要扩展出创建
FactoryBean 对象的能力,所以这就想一个链条服务上,截出一个段来处理额外的服务,并把链条再链接上。 - 此处新增加的功能主要是在 doGetBean 方法中,添加了调用
(T) getObjectForBeanInstance(sharedInstance, name)对获取
FactoryBean 的操作。 - 在 getObjectForBeanInstance 方法中做具体的 instanceof 判断,另外还会从 FactoryBean 的缓存中获取对象,如果不存在则调用
FactoryBeanRegistrySupport#getObjectFromFactoryBean,执行具体的操作。
总结
-
在 Spring 框架整个开发的过程中,前期的各个功能接口类扩展的像膨胀了似的,但到后期在完善功能时,就没有那么难了,反而深入理解后会觉得功能的补充,都比较简单。只需要再所遇领域范围内进行扩展相应的服务实现即可。
-
当仔细阅读完关于 FactoryBean 的实现以及测试过程的使用,以后再需要使用 FactoryBean 开发相应的组件时候,一定会非常清楚它是如何创建自己的复杂
Bean 对象以及在什么时候初始化和调用的。遇到问题也可以快速的排查、定位和解决。