前言
在spring中FactoryBean绝对是一种神奇的存在,和BeanFactory经常混淆,而且成为面试过程中经常被问到的问题,其实FactoryBean和BeanFactory很好理解,掌握一定的技巧即可。
初识
FactoryBean翻译过来是工厂Bean,BeanFactory翻译过来是Bean工厂,前者是bean工厂beanFactory中的一个bean,只不过这个bean和一般的bean不一样,它有着自己的特殊之处,特殊在什么地方那,在spring中提供了FactoryBean的接口,
package org.springframework.beans.factory; import org.springframework.lang.Nullable; public interface FactoryBean<T> { @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
FactoryBean接口很简单,就提供了三个方法getObject、getObjectType、isSingleton。就是这三个方法却成为了spring中很多功能的基础,搜索整个spring的源码可以找到很多FactoryBean,除了spring自身提供的以外,在和一些框架进行集成的时候,同样有FactoryBean的影子,比如和mybatis集成的时候的SqlSessionFactoryBean,
用法
这里以springboot的环境为例演示下FactoryBean的用法,有需要源码的可关注公众号【北漂程序员】私聊我。
自定义FactoryBean,仅在getObject方法内自己new了一个Student对象,且返回该对象;重写了toString方法,为了测试用。
package com.example.myDemo.component; import com.example.myDemo.po.Student; import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Component; @Component public class MyFactoryBean implements FactoryBean<Student> { @Override public Student getObject() throws Exception { Student student=new Student(); return student; } @Override public Class<?> getObjectType() { return null; } @Override public String toString() { return "MyFactoryBean{}"; } }
下面是Student类,很简单就两个属性且重写了toString方法,
package com.example.myDemo.po; public class Student { private String name; private String code; public Student(String name, String code) { this.name = name; this.code = code; } public Student() { } @Override public String toString() { return "Student{}"; } }
下面就是测试的方法了,
package com.example.myDemo; import com.example.myDemo.component.MyFactoryBean; import com.example.myDemo.po.Student; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.context.ApplicationContext; @SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) public class MyDemoApplication { public static void main(String[] args) { ApplicationContext ac=SpringApplication.run(MyDemoApplication.class, args); //获得Student对象 Student stu=(Student) ac.getBean("myFactoryBean"); //获得MyFactoryBean对象 MyFactoryBean myFactoryBean=(MyFactoryBean) ac.getBean("&myFactoryBean"); System.out.println("stu:"+stu); System.out.println("myFactoryBean:"+myFactoryBean); } }
先看下打印结果,
打印结果很奇怪通过“myFactoryBean”获得了Student对象,通过“&myFactoryBean”获得了MyFactoryBean对象。为什么会这样
功能解释
看了上面的输出结果很多小伙伴都很诧异,没错这就是FactoryBean的神奇,通俗点讲FactoryBean是一个工厂bean,它是一种可以生产bean的bean,通过其getObejct方法生产bean。当然不论是FactoryBean还是FactoryBean生产的bean都是受spring管理的这点是没有问题的,不然通过getBean方法是拿不到的。
上面讲了那么多到底FactoryBean的用处是什么,前面讲到FactroyBean的作用是生产一个Bean,这里有一个疑问spring就是用来生产bean和管理bean的,为什么还要有FactoryBean,FactoryBean的真正目的是让开发者自己去定义那些复杂的bean并交给spring管理,如果bean中要初始化很多变量,而且要进行许多操作,那么使用spring的自动装配是很难完成的,所以spring的开发者把这些工作交给了我们。一个比较常见的例子是,在mybatis和spring集成的时候便有这样一个FactoryBean,名字叫SqlSessionFactoryBean,这个FactoryBean的目的就是返回一个spring管理的SqlSessionFactory,使用过mybatis的都知道要创建一个sqlSessionFactory需要配置很多属性,所以便有了SqlSessionFactoryBean,下面看下SqlSessionFactoryBean,
看下sqlSessionFactoryBean的getObejct方法
public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { this.afterPropertiesSet(); } return this.sqlSessionFactory; }
getObejctType方法
public Class<? extends SqlSessionFactory> getObjectType() { return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass(); }
isSingleton方法
public boolean isSingleton() { return true; }
总结
本篇文章主要带小伙伴了解了FactoryBean这种特殊的Bean,它的作用就是生产Bean。这里有个疑问在使用getBean方法的时候,为什么传入“myFactoryBean”和“&MyFactoryBean”两个值返回值一个是FactoryBean生产的bean,一个是FactorBean那,下篇通过源码来揭秘,揭秘getObjectForBeanInstance方法的那些事,欢迎关注。