一、什么是FactoryBean

FactoryBean是由spring提供的用来让用户可以自定bean创建的接口;实现该接口可以让你的bean不用经过spring复杂的bean创建过程,但同时也能做到拿来即用,按需加载;该接口提供的方法如下:

/**
* 获取FactoryBean管理的对象的实例 一般由spring自动调用 无需手动调用
*/
T getObject() throws Exception; /**
* 获取FactoryBean管理的对象的类型
*/
Class<?> getObjectType(); /**
* 判断FactoryBean管理的对象是否是单例 默认为单例
* 如果返回为false,则spring不会使用factoryBeanObjectCache来缓存已加载的对象实例,
* 每次都会创建一个全新的对象
*/
default boolean isSingleton() {
return true;
}

二、FactoryBean在spring中的加载过程

     测试环境准备:

  1. 自定义一个FactoryBean实现类,返回对应的测试实例Person类,代码如图:
  2. 为了便于代码debug,使用xml的配置方式进行配置,如图:
  3. 启动代码如下:通过以上环境debug可以发现,当spring容器加载完后在BeanFactory的一级缓存singletonObjects中有myFactoryBean而并没有person类的实例,那ac.getBean("myFactoryBean")是怎么拿到Person的呢我们可以通过剖析getBean("myFactoryBean")这个方法来进行分析:当spring想要获取某个bean的时候,首先会从缓存中获取这个bean(参加org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)),当需要获取myFactoryBean时,由于xml中有对myFactoryBean的配置所以容器启动的时候myFactoryBean就已经被存到缓存中去了,所以从缓存中能直接获取,接下来会调用专门针对加载实现了FactoryBean接口的实现类的方法:getObjectForBeanInstance()==》getObjectFromFactoryBean()==》doGetObjectFromFactoryBean;其中会在doGetObjectFromFactoryBean中调用getObject方法返回具体的对象实例,getObjectFromFactoryBean方法中会根据isSingleton方法的具体实现判断要不要把对应实例加载到factoryBeanObjectCache缓存中;下面贴上这个三个核心方法的方法签名和源码:

org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance:

protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
/**
* Don't let calling code try to dereference the factory if the bean isn't a factory.
* 判断是否是FactoryBean的子接口,是则设置isFactoryBean为true并返回
*/
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
} // Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 判断我们拿到的bean实例是不是factoryBean,如果不是直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
} Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 从factoryBean的缓存factoryBeanObjectCache中尝试获取bean信息
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 调用getObject获取factoryBean管理的bean实例
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

            org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean:

点击查看代码
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}

          org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean:

点击查看代码
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
} // Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}

三、FactoryBean和BeanFactory的区别

  1.  BeanFactoryBeanFactory是spring定义的创建bean的一个顶层父接口,其定义了获取bean的方法,咱们常见的ApplicationContext和DefaultListableBeanFactory都间接实现了它;实现了BeanFactory意味着创建的bean必须要经过spring定义的复杂的各种生命周期方法;
  2. FactoryBeanFactoryBean同样可以创建bean,但是其管理的bean可以不经过spring定义的创建的bean的生命周期,也可以不通过反射直接获取;可以针对不同的需求定制化FactoryBean,相当于一个创建工厂的bean,而这个工厂bean又可以创建不同的对象实例

四、FactoryBean的实际运用场景

据我所知像Mybatis,dubbo以及springcloud这些开源框架中都有使用factoryBean来创建对象,但是由于本人并没有去看这些框架的源码也没有过多的了解所以这里暂且不表,所以在这里贴一个通过FactoryBean创建定时任务的例子;

项目中定时任务的使用还是比较频繁的,设置有时候会多到专门开一个服务器去跑这些定时任务,而定时任务无非关注几点,一是任务的间隔时间,二是任务的执行逻辑;

  1. 定义一个CommonTask来统一管理任务的间隔时间以及具体执行的service;
  2. 定义TaskFactoryBean实现FactoryBean接口,用来生成CommonTask的实例
  3. 定义一个TaskConfig类用来按需生成不同的CommonTask以上只是提供了粗略的实现思路,具体的等抽空补代码。。。

最新文章

  1. Linux Kernel中获取当前目录方法(undone)
  2. 微信扫码支付asp.net(C#)实现步骤
  3. Java处理InterruptedException异常小结
  4. PagedList.MVC 应用
  5. Dynamics CRM 2013 初体验(5):Business Rule
  6. C#与lua相互调用
  7. MySQL InnoDB表压缩
  8. AI - TensorFlow - 可视化工具TensorBoard
  9. Windows 10的最新版1803版本ISO下载
  10. 【BZOJ1578】【USACO2009Feb】股票市场 背包DP
  11. CGAffineTransform 缩放 / 旋转 / 平移
  12. oracle创建用户和角色、管理授权以及表空间操作
  13. Android-Toolbar相关
  14. idea 配置svn
  15. 554C - Kyoya and Colored Balls
  16. Oracle单节点_Grid_Infrastructure_DB_安装过程图解(三/三)
  17. 转载:QTableView中嵌入可视化组件
  18. mysql入门与进阶
  19. Codeforces Round #482 (Div. 2) :B - Treasure Hunt
  20. pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/simple

热门文章

  1. Manacher算法讲解——字符串最长回文子串
  2. 网卡限速工具之WonderShaper
  3. Springboot连接数据库
  4. lombok Builder注解
  5. Macos下用pycharm运行django项目死活安装不上mysqlclient怎么办!!??
  6. 利用 Gitea Doctor自助诊断工具帮助管理员排查问题
  7. 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(完)
  8. 【pytest官方文档】解读- 如何安装和使用插件
  9. 华南理工大学 Python第6章课后测验-2
  10. PLM产品生命周期管理,包含哪些阶段?