最近做一个需求,想在xml配置文件中引入注解@Bean声明的对象,
并且在这个bean注册到spring容器之前实现数据集合的提前注入,在xml中也可以做到注入集合但是不如代码灵活,如果注入的是一段业务逻辑操作xml无法实现。其实是用到了spring注解和xml配置的交叉使用,以前都是单使用注解偏多,导致对于spring容器中bean实例化没有清晰的关注,先上代码:
通过使用注解@Configuration和注解@Bean添加name属性名称,替换掉之前在xml中配置的bean,实现对象注册到容器之前能够自定义业务执行。如果在项目代码其他位置使用该对象,直接使用注解@Resource(name = "myItemReader")依赖注入,从容器中自动获取bean。工作大多使用注解@Autowired,根据类型装配注入,结合注解@Qualifier能够实现@Resource一样的效果根据名称来注入。到这里不禁想到@Configuration和注解@Bean这种基于Java类的配置方式是spring3.0开始支持,在springboot中比较常见,那么在spring2.5之前,如果用xml的方式实现复杂的Bean呢,这就说到了本文要讲的FactoryBean。
FactoryBean首先是一个特殊的Bean,通常是用来创建比较复杂的bean,一般的bean 直接用xml配置,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。
FactoryBean跟普通的Bean不同之处在于,其通过getBean("id")方法返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象。FactoryBean结合了 工厂模式和装饰器模式,实现对复杂Bean的实现,有的人会问,既然现在已经可以使用基于Java类的配置方式实现,何必去了解FactoryBean,对于简单的业务开发,不使用FactoryBean当然没有问题,但当你要开发一个第三方插件的时候,希望你开发的插件不管是在spring的哪个版本都可以适用,FactoryBean就能够体现它的作用,这也就是为什么我们在spring整合的一些第三方插件的时候,会在xml配置文件中频繁看到框架自定义的一些FactoryBean,比如Spring整合Mybatis:
下图是单独使用Mybatis时,直接添加依赖,配置数据源,创建SqlSessionFactory,就可以使用Mybatis执行CRUD。
但当spring整合Mybatis时,需要添加包mybatis-spring,并且在配置文件中做如下配置:
查看源码,SqlSessionFactoryBean实现了FactoryBean接口,作用很明显是向spring容器中注册了一个SqlSessionFactory,通过以上总结FactoryBean是spring提供用来创建复杂bean的接口。
接下来再说BeanFactory:
BeanFactory接口是Spring实现IOC的关键所在,通过了解BeanFactory之后才能更好的理解今天想讲的Spring中的BeanFactory和FactoryBean区别,单从名称来判断也可以发现一个是Bean工厂一个是Bean,而且从spring真正的底层实现上来看,这两个东西并不应该放在一起去比较,根本不是一类的接口,所以在找不同之前,先拿BeanFactory和ApplicationContext来对比,辅助理解BeanFactory:
上图是不完整的BeanFactory接口关系图,但是足以体现BeanFactory和ApplicationContext的关系,BeanFactory是最顶层的接口,ApplicationContext由它派生而来,因为老的BeanFactory接口无法满足不断更新的spring的需求,于是ApplicationContext就基本上代替了BeanFactory作为容器的工作。
上面是spring启动类,我们常用的就是ApplicationContext接口的实现类来完成了Xml配置文件的加载。而几乎抛弃了去使用BeanFactory。主要是ApplicationContext相较于BeanFactory的优势有以下几点:
1、ApplicationContext会在初始化的时候就加载并且检查,BeanFacotry是延迟加载,这样的好处是可以及时检查依赖是否完全注入
2、BeanFactory是最顶层的接口,ApplicationContext由它派生而来,所以提供了BeanFactory的所有功能
3、ApplicationContext是一种更加面向框架的工作方式以及对上下文进行分层和实现继承,很好的支持诸如AOP、Web应用等许多插件
4、BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册
5、ApplicationContext还有额外的一些其他功能,MessageSource,提供国际化的消息访问功能,资源访问,如URL和文件,事件传播,载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定的层次,比如应用的Web层。这里的每一个功能都值得单独开一篇去说,但是本文注重点在于区分BeanFactory和FactoryBean就不扩展去说。
综上,BeanFactory和FactoryBean的共同点都是接口,其接口功能完全不同,所以当学习这两个接口的时候,我认为应该分开理解,不能混为一谈,但毕竟都是spring中的接口,而BeanFactory又是最顶层的接口,实现IOC容器的关键,所以还有一个关联就是FactoryBean是由BeanFactory支持的、用来暴露bean实例的接口,所以也有概念上的包含与被包含的涵义。