本文主要是介绍实例区别BeanFactory和FactoryBean,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
从代码角度写了一个帖子去解释BeanFactory和FactoryBean,感概下Mybatis对Spring框架用的炉火纯青的水平。更多Spring内容进入【Spring解读系列目录】。
BeanFactory
什么是BeanFactory?看名字也能明白这是一个工厂,其实是Spring框架中的一个顶层类。是Spring提供的一个工厂,能够产生注册在Spring中的对象。比如BeanFactory.getBean()
,就可以拿到一个bean
的实例对象。或者实例化AnnotationConfigApplicationContext
类就可以拿到其对象,也就是说BeanFactory
是为了产生对象使用的。这个其实没什么好讲的,重点就在于FactoryBean
。
BeanFactory bean=new AnnotationConfigApplicationContext();
bean.getBean("service");
FactoryBean
FactoryBean
是Spring中的一个特殊的bean
。什么是bean
呢?其实只要一个类交给Spring容器管理就可以称作一个Bean
,也可以直接说就是一个对象。那FactoryBean
有什么特殊性呢?那就是FactoryBean
可以构造一个新的bean
出来。我们先用一个例子来简单说下,先创建一个测试类TestDaoFactoryBean
,然后创建一个MyDaoFactroyBean
类实现FactoryBean
,再实现里面的方法,起个名字叫factoryBeanTest
。
public class TestDaoFactoryBean { }
@Component("factoryBeanTest")
public class MyFactroyBean implements FactoryBean {@Overridepublic Object getObject() throws Exception {return new TestDaoFactoryBean(); //getObject返回新构建的类}@Overridepublic Class<?> getObjectType() {return TestDaoFactoryBean.class;}@Overridepublic boolean isSingleton() { //设置单例模式return true;}
}
构建完成以后我们就尝试去把MyFactroyBean
拿出来,所以我们用一个Test类取一下:
public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext anno=new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(anno.getBean("factoryBeanTest"));}
}
打印结果:
com.demo.dao.TestDaoFactoryBean@701fc37a
最终运行的结果发现取出来的并不是MyFactroyBean
,而是我们在getObject()
这个方法里返回的对象。那么怎么拿到MyFactroyBean
呢,只要把名字前面加一个”&”
符号就可以了
System.out.println(anno.getBean("&factoryBeanTest"));
打印结果:
com.demo.dao.MyFactroyBean@701fc37a
为什么会这样呢?先不解释,不过根据这个现象我们总结一下:
如果一个类实现了FactoryBean
,那么Spring容器中就会生成两个对象,一个是getObject()
方法返回的对象,还有一个是当前的对象(也就是this
本身)。getObject()
对象存的是指定的对象,在Bean
上指定名字的对象。当前对象是存的是”&”+当前类的名字
。
FactoryBean的作用
要想解释为什么Spring要这样设计,首先我们看先看FactoryBean
有什么具体的作用。做一个假设,我们需要引用第三方的一个jar包,这里面有一个配置类A
,而这个配置类A
又依赖了其他100个类
。那么请问,这个其他的100个类
的依赖,应该由谁去管理呢?不管由谁管理,一定不是让使用者管理对不对,我们期望的是在Spring中配置了一个A的bean
,就可以正常使用这个jar包了,而不是说要使用者把A
中所有的依赖都维护一遍,这显然不合理。比如我们经常使用的Mybatis就是一个非常经典的例子。
一般来说都会把Mybatis交给Spring管理,如果Mybatis里面使用的第三方的类也都需要开发人员去维护是不是极为不合理。所以我们期望就是Mybatis自己维护好自己的关系,然后提供一个bean
(对象)出来,我只要维护这个bean
就可以完成Spring的管理了。以Mybatis中的SqlSessionFactory
为例。如果要我们自己配Spring依赖关系,首先要配一个SqlSessionFactory
的bean
,然后发现里面依赖了Configuration
对象,又要配置一堆依赖关系,配完以后Configuration
对象又依赖了Environment
对象和好几十个其他对象,要一个一个配bean
出来,单单交给Spring管理那就是一个相当巨大的工程了,还不如自己写来的简单。所以最好的办法就是Mybatis自己把这一切的关系都维护好了,使用者只要引用SqlSessionFactory
一个bean就搞定了,这个时候FactoryBean
就有大作用了。Mybatis也提供了这样一个bean
叫做SqlSessionFactoryBean
就做了这样一个事情。
#Mybatis提供的FactorBean:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {...private SqlSessionFactory sqlSessionFactory;...@Overridepublic SqlSessionFactory getObject() throws Exception {if (this.sqlSessionFactory == null) {afterPropertiesSet();}return this.sqlSessionFactory;}...
}
这个类也实现了FactoryBean
,虽然叫做SqlSessionFactoryBean
但是它最终返回的是SqlSessionFactory
。在SqlSessionFactoryBean
中Mybatis就把Configuration
,Environment
等等这些对象提前初始化,并且用setter
方法赋值,那么最终我们拿到的bean
就是已经初始化好了对象直接可以用。
FactoryBean使用范例
所以为了加深理解,我们也可以做一个例子,首先我们改造一下TestDaoFactoryBean
让其具备一些属性。
public class TestDaoFactoryBean {private String a1;private Integer a2;public String getA1() {return a1;}public void setA1(String a1) {this.a1 = a1;}public Integer getA2() {return a2;}public void setA2(Integer a2) {this.a2 = a2;}
}
然后修改MyFactroyBean
,并且在里面初始化TestDaoFactoryBean
。
@Component("factoryBeanTest")
public class MyFactroyBean implements FactoryBean {@Overridepublic Object getObject() throws Exception {TestDaoFactoryBean factoryBean=new TestDaoFactoryBean();factoryBean.setA1("a1");factoryBean.setA2(22222);return factoryBean;}@Overridepublic Class<?> getObjectType() {return TestDaoFactoryBean.class;}@Overridepublic boolean isSingleton() {return true;}
}
最后获取一下,这样我们就完成了TestDaoFactoryBean
的初始化赋值,外部如果要使用就会发现其中的属性a1
和a2
已经被构建过了。
public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext anno=new AnnotationConfigApplicationContext(AppConfig.class);TestDaoFactoryBean factoryBean= (TestDaoFactoryBean) anno.getBean("factoryBeanTest");System.out.println("getA1:"+factoryBean.getA1());System.out.println("getA2:"+factoryBean.getA2());}
}
打印结果:
getA1:a1
getA2:22222
但是要注意,实现了FactoryBean
的本身是和别的bean
没有区别的,唯一的区别就是返回的对象要指定,因此这些实现了FactoryBean
的bean
也可以进行业务实现。当然这点要根据具体的业务具体去分析。
总结
举个不恰当的例子BeanFactory
是个鞋厂,FactoryBean
就是一个特殊的鞋子,这个鞋子能够根据需求产生新的鞋子,这么牛逼的鞋子,就问你服不服。从名字上看BeanFactory
是bean
工厂只能生产bean
。而FactoryBean
是一个bean
(对象),但是这个bean
能够生产新的bean
。好绕,大家理解下。
那么如果有人问道这两个的区别,大概可以这样说:BeanFactory
是Spring容器当中的工厂,它能生产我们交给Spring的类,并且获取这些类的对象。FactoryBean
只是Spring中的一个特殊的bean
接口,FactoryBean
需要被实现三个方法,实现以后可以返回一个新的bean
,这个新的bean
就是getObject()
返回出去的对象。并且存在的形式也不同,得到FactoryBean
本身需要用&+类名
,而要得到FactoryBean
产生的对象则要使用真实指定的bean
名字。
这篇关于实例区别BeanFactory和FactoryBean的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!