连云港做网站建设,哈尔滨招标信息网官网,海淀注册公司,住房和城乡建设部官网进行查询前言FactoryBean是一个有意思#xff0c;且非常重要的扩展点#xff0c;之所以说是有意思#xff0c;是因为它老是被拿来与另一个名字比较类似的BeanFactory来比较#xff0c;特别是在面试当中#xff0c;动不动就问你#xff1a;你了解Beanfactory和FactoryBean的区别吗…前言FactoryBean是一个有意思且非常重要的扩展点之所以说是有意思是因为它老是被拿来与另一个名字比较类似的BeanFactory来比较特别是在面试当中动不动就问你你了解Beanfactory和FactoryBean的区别吗其实两个是完全不同的接口如果非要说出有什么明显区别大概就是名字吧。为什么又说非常重要呢那是因为在创建一些比较复杂的bean的时候常规的方式不能使用就可以考虑使用FactoryBean特别其他框架技术与Spring集成的时候如mybatis与Spring的集成大家都知道mybatis是通过SqlSessionFactory创建出Sqlsession来执行sql的那么Service层在调用Dao层的接口来执行数据库操作时肯定得持有SqlSessionFactory那么问题来了Spring容器怎么才能持有SqlSessionFactory呢答案就是SqlSessionFactoryBean它实现了FactoryBean接口。既然FactoryBean如此神奇那么就先盘一盘它的主要功能特性然后再通过一个示例来验证一下最后再深入盘一盘其工作原理 。功能特性1、FactoryBean接口有三个方法1、getObject()用于获取bean主要应用在创建一些复杂的bean的场景2、getObjectType()用于获取返回bean的类型3、isSingleton()用于判断返回bean是否属于单例默认trure通俗说就是工厂bean2、BeanFactory是Spring bean容器的根接口ApplicationContext是Spring bean容器的高级接口继承于BeanFactory通俗理解就是生成bean的工厂所以FactoryBean与BeanFactory本质上是完全不同的两个接口。既然完全不同又说什么区别呢至少我是这么认为的。实现方式那么FactoryBean怎么用呢这里先举一个场景假如需要要创建一个特别复杂的类Computer1、定义Computer类Slf4j
public class Computer {private String type;public String getType() {return type;}public void setType(String type) {this.type type;}public Computer() {log.info(----Computer类无参数构造方法触发执行);}public Computer(String type) {this.type type;log.info(----Computer类有参数构造方法触发执行);}
}2、定义ComputerFactoryBean实现FactoryBean接口实现了getObject()创建了一个“复杂”的Bean在getObjectType()返回了Bean的类型在isSingleton()指定Bean的作用域为单例Component
Slf4j
public class ComputerFactoryBean implements FactoryBean {private String name ComputerFactoryBean本尊;public ComputerFactoryBean() {log.info(----ComputerFactoryBean无参数构造方法触发执行);}Overridepublic Object getObject() throws Exception {log.info(----com.fanfu.bean.ComputerFactoryBean.getObject()触发执行-start);Computer computer new Computer(商用笔记本电脑);log.info(----com.fanfu.bean.ComputerFactoryBean.getObject()触发执行-end);return computer;}Overridepublic Class? getObjectType() {return Computer.class;}Overridepublic boolean isSingleton() {return true;}
}
3、编写单元测试从Spring容器中取出beanName为computeFactoryBean的bean通常情况下如果ComputerFactoryBean未实现FactoryBean接口getBean(computeFactoryBean)的结果是computeFactoryBean对象而实现了FactoryBean接口getBean(computeFactoryBean)的结果的是getObject()方法中返回的结果即computer这就是FactoryBean如此神奇的地方。Test
public void test6() {log.info(----单元测试执行开始);log.info(----Spring容器实例化开始);AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(com.fanfu);log.info(----Spring容器实例化完成);ComputerFactoryBean computerFactoryBean ((ComputerFactoryBean) context.getBean(computerFactoryBean));Computer computer (Computer) context.getBean(computerFactoryBean);Assert.isTrue(computerFactoryBean.getClass().getName().equals(com.fanfu.bean.ComputerFactoryBean));Assert.isTrue(computer.getClass().getName().equals(com.fanfu.entity.Computer));log.info(----单元测试执行完毕);
}单元测试结果工作原理 从单元测试验证结果来看ComputerFactoryBean本尊在Spring容器实例化的过程中就以非懒加载的单例bean实例化完成注册到了Spring容器里。顺着context.getBean(computerFactoryBean)往下跟踪会发现接着调用了AbstractApplicationContext#getBean(java.lang.String)--AbstractBeanFactory#getBean(java.lang.String)--AbstractAutowireCapableBeanFactory#getObjectForBeanInstance()--AbstractBeanFactory#getObjectForBeanInstance()到这是一个关键点1、AbstractBeanFactory#getObjectForBeanInstance()中判断是否bean是否是一个工厂引用即beanName是否是“”开头如果beanName是以“”开头则直接返回本尊如果不是则继续向下执行2、检查bean是否实现了FactoryBean接口如果获取的bean没有实现FactoryBean接口则直接返回如果获取的bean实现了FactoryBean接口则继续向下执行3、对获取的bean强制转换为FactoryBean然后去执行FactoryBean接口实现类的getObject()protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, Nullable RootBeanDefinition mbd) {//检查bean是否是一个工厂引用即beanName是否是“”开头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;}//如果beanName是以“”开头则直接返回本尊return beanInstance;}//如果获取的bean没有实现FactoryBean接口则直接返回if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}Object object null;if (mbd ! null) {mbd.isFactoryBean true;}else {object getCachedObjectForFactoryBean(beanName);}if (object null) {// 如果获取的bean实现FactoryBean接口则对bean进行强制转换FactoryBean? factory (FactoryBean?) beanInstance;if (mbd null containsBeanDefinition(beanName)) {mbd getMergedLocalBeanDefinition(beanName);}boolean synthetic (mbd ! null mbd.isSynthetic());//去执行FactoryBean接口实现类的getObject()object getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;
}
总结总体来讲从FactoryBean的实现方式到工作原理都很简单同时也是有大用处的扩展点特别要必要牢牢掌握。当然如果有面试官再问你FactoryBean与BeanFactory有什么区别的时候不要再犹豫直接告诉他”FactoryBean与BeanFactory本身并没有什么区别但是我可以分别给你介绍介绍这两个接口有什么用处。FactoryBean是一个工厂Bean在需要创建比较复杂的bean的时候可以用到BeanFactory是Spring bean容器的根接口也就是说实现BeanFactory可以得到一个最基础的Spring容器Spring中的所有高级容器都继承了这个根接口。“如果你能这样回答这个问题相信会给面试官留下一下好印象的。