对象作用域和FactoryBean

FactoryBean

FactoryBean是一个工厂Bean,它使用到工厂方法模式,可以代理生成一个实例

为什么使用FactoryBean

在之前的设计中, Spring IoC 容器通过反射或字节码增强的方式实例化 Bean,但有些情况下,实例化较复杂,要往 xml 里 <bean> 填写大量的配置信息,且过程不能为用户支配。就像我们之前的实现,要注册 UserService,还要在 xml 配置内部的 UserDao,万一以后又多了一个 EventDao 了呢?当需要往 xml 配置里塞的东西越来越多,本来简单的操作,也会变成庞大,难以理解的屎山。

FactoryBean 很好的解决了这一点,它是一个对用户暴露的客制化 Bean 实例化的接口,用户可以通过实现该接口定制实例化Bean的逻辑。可以隐藏实例化一些复杂Bean的细节。给上层应用带来便利。说人话就是,将一个待实例化的 bean 内部所有自定义类型都丢到 FactoryBean 代理。

将对象交由Spring管理的方式:

  1. 使用XML配置文件标签;
  2. 在自定义类上使用@Component注解(将自定义对象交由Spring管理)
  3. 使用FactoryBean灵活的创建出对象,然后使用XML或者@Component注解交由Spring管理。
  4. 使用@Bean注解(灵活的创建对象,并放入Spring容器中);

怎么用

  • FactoryBean 一般用于创建较为复杂的 Bean,一般的bean使用XML配置即可,但若是一个Bean的创建过程中涉及到很多其他 Bean 和 复杂的逻辑,使用XML配置比较复杂的话,这时可以考虑使用FactoryBean。
  • 定时任务可以由 FactoryBean 实现
  • Mapper 类都是接口,无法被实例化,Mybatis 是通过 FactoryBean 对象创建 Mapper 对象的代理对象,完成 Mapper 接口的注入

工程

还是那句老话,类与类之间各司其职,防止代码耦合

在 AbstractBeanFactory 继承的 DefaultSingletonBeanRegister 类中间加一层 FactoryBeanRegisterSupport ,这个类在 Spring IoC 框架中主要是用于处理 Factory Bean 注册的支撑操作

BeanDefinition

singleton、prototype,是本次在 BeanDefinition 类中新增加的两个属性信息,用于把从 spring.xml 中解析到的 Bean 对象作用范围填充到属性中

创建 FactoryBean 接口

public interface FactoryBean<T> {

T getObject() throws BeansException;

Class<?> getObjectType();

boolean isSingleton();

}

实现 FactoryBean 注册服务

  • 从缓存中获取 FactoryBean,要是没有通过 Factory.getObject 获取并存入缓存中,如果是原型就直接从 Factory.getObject 获取

扩展 AbstractBeanFactory 创建对象的逻辑

​ 在之前的设计中,没有考虑到 Bean 有可能为原型模式,每次获取完 Bean 后就将对象放入缓存中供下一次调取。AbstractBeanFactory 简单继承 DefaultSingletonBeanRegistry,经过这次的设计,我们在 AbstractBeanFactory 和 DefaultSingletonBeanRegistry 之间加入 FactoryBeanRegisterSupport 进行过渡。即扩展出创建 FactoryBean 对象的能力并区分 Bean 到底是单例还是原型

  • 从缓存中获取 FactoryBean,要是没有通过 Factory.getObject 获取并存入缓存中,如果是原型就直接从 Factory.getObject 获取 ### 扩展 AbstractBeanFactory 创建对象的逻辑 在之前的设计中,没有考虑到 Bean 有可能为原型模式,每次获取完 Bean 后就将对象放入缓存中供下一次调取。AbstractBeanFactory 简单继承 DefaultSingletonBeanRegistry,经过这次的设计,我们在 AbstractBeanFactory 和 DefaultSingletonBeanRegistry 之间加入 FactoryBeanRegisterSupport 进行过渡。即扩展出创建 FactoryBean 对象的能力并区分 Bean 到底是单例还是原型

  • 从缓存中获取 FactoryBean,要是没有通过 Factory.getObject 获取并存入缓存中,如果是原型就直接从 Factory.getObject 获取 ### 扩展 AbstractBeanFactory 创建对象的逻辑 在之前的设计中,没有考虑到 Bean 有可能为原型模式,每次获取完 Bean 后就将对象放入缓存中供下一次调取。AbstractBeanFactory 简单继承 DefaultSingletonBeanRegistry,经过这次的设计,我们在 AbstractBeanFactory 和 DefaultSingletonBeanRegistry 之间加入 FactoryBeanRegisterSupport 进行过渡。即扩展出创建 FactoryBean 对象的能力并区分 Bean 到底是单例还是原型

总结

​ FactoryBean 是用于获取Bean,但和 BeanFactory 不太一样,BeanFactory 获取的是静态的类,就比如我们写的 Service 的各个实现类,它的逻辑就是我拿到你的 Bean 定义,然后一步步构造后作为 Spring 的 Bean。 FactoryBean 不关心怎么构造出来这个 Bean,对于他来讲,只要你实现了我的 getObject() 方法,我就能拿到你这个 Bean,这样他就更灵活,可以给一些第三方来用。 现实中的例子,Mybatis 的 Dao,我们使用 Dao 时,只需要写一个 Dao 的接口可以,这就是 Mybatis 通过 FactoryBean 实现了一个MapperFactoryBean 可以获取到一个 BaseMapepr ,其中封装了可以从数据库获取数据的 CURD 等操作,这样我们写 DAO 只需要继承BaseMapper,MapperFactoryBean 会帮我们把 BaseMapper 所有实现的DAO都注入,并在其中封装好查询操作,我们使用时啥都不需要关心。 也就是说,FacotryBean 可以帮我们注入一类 Bean,这类 Bean 所需要的通用依赖或者信息我们可以通过 FactoryBean 实现类统一处理,并注入。