Spring 的 BeanFactory 和 FactoryBean 傻傻分不清?
beanfacotry是spring中比较原始的factory。如xmlbeanfactory就是一种典型的beanfactory。原始的beanfactory无法支持spring的许多插件,如aop功能、web应用等。
applicationcontext接口,它由beanfactory接口派生而来。
applicationcontext包含beanfactory的所有功能,通常建议比beanfactory优先。
beanfactory和factorybean的区别
beanfactory是接口,提供了oc容器最基本的形式,给具体的ioc容器的实现提供了规范,factorybean也是接口,为ioc容器中bean的实现提供了更加灵活的方式,factorybean在ioc容器的基础上给bean的实现加上了一个简单工厂模式和装饰模式(如果想了解装饰模式参考:修饰者模式(装饰者模式,decoration) 我们可以在getobject()方法中灵活配置。其实在spring源码中有很多factorybean的实现类.
区别:beanfactory是个factory,也就是ioc容器或对象工厂,factorybean是个bean。在spring中,所有的bean都是由beanfactory(也就是ioc容器)来进行管理的。
但对factorybean而言,这个bean不是简单的bean,而是一个能生产或者修饰对象生成的工厂bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
1、beanfactory
beanfactory,以factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在spring中,beanfactory是ioc容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
beanfactory只是个接口,并不是ioc容器的具体实现,但是spring容器给出了很多种实现,如 defaultlistablebeanfactory、xmlbeanfactory、applicationcontext等,其中xmlbeanfactory就是常用的一个,该实现将以xml方式描述组成应用的对象及对象间的依赖关系。xmlbeanfactory类将持有此xml配置元数据,并用它来构建一个完全可配置的系统或应用。
都是附加了某种功能的实现。它为其他具体的ioc容器提供了最基本的规范,例如defaultlistablebeanfactory,xmlbeanfactory,applicationcontext 等具体的容器都是实现了beanfactory,再在其基础之上附加了其他的功能。
beanfactory和applicationcontext就是spring框架的两个ioc容器,现在一般使用applicationncontext,其不但包含了beanfactory的作用,同时还进行更多的扩展。
beanfacotry是spring中比较原始的factory。如xmlbeanfactory就是一种典型的beanfactory。
原始的beanfactory无法支持spring的许多插件,如aop功能、web应用等。applicationcontext接口,它由beanfactory接口派生而来。
applicationcontext包含beanfactory的所有功能,通常建议比beanfactory优先
applicationcontext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,applicationcontext包还提供了以下的功能:
-
messagesource, 提供国际化的消息访问
-
资源访问,如url和文件
-
事件传播
-
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层;
在不使用spring框架之前,我们的service层中要使用dao层的对象,不得不在service层中new一个对象。
存在的问题:层与层之间的依赖。service层要用dao层对象需要配置到xml配置文件中,至于对象是怎么创建的,关系是怎么组合的都交给了spring框架去实现。
方式1、
resource resource = new filesystemresource("beans.xml"); beanfactory factory = new xmlbeanfactory(resource);
方式2、
classpathresource resource = new classpathresource("beans.xml"); beanfactory factory = new xmlbeanfactory(resource);
方式3、
applicationcontext context = new classpathxmlapplicationcontext(new string[] {"applicationcontext.xml", "applicationcontext-part2.xml"}); beanfactory factory = (beanfactory) context;
基本就是这些了,接着使用getbean(string beanname)方法就可以取得bean的实例;beanfactory提供的方法及其简单,仅提供了六种方法供客户调用:
boolean containsbean(string beanname) 判断工厂中是否包含给定名称的bean定义,若有则返回true
object getbean(string) 返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常。
object getbean(string, class) 返回以给定名称注册的bean实例,并转换为给定class类型。
class gettype(string name) 返回给定名称的bean的class,如果没有找到指定的bean实例,则排除nosuchbeandefinitionexception异常
boolean issingleton(string) 判断给定名称的bean定义是否为单例模式
string[] getaliases(string name) 返回给定bean名称的所有别名
package org.springframework.beans.factory; import org.springframework.beans.beansexception; public interface beanfactory { string factory_bean_prefix = "&"; object getbean(string name) throws beansexception; <t> t getbean(string name, class<t> requiredtype) throws beansexception; <t> t getbean(class<t> requiredtype) throws beansexception; object getbean(string name, object... args) throws beansexception; boolean containsbean(string name); boolean issingleton(string name) throws nosuchbeandefinitionexception; boolean isprototype(string name) throws nosuchbeandefinitionexception; boolean istypematch(string name, class<?> targettype) throws nosuchbeandefinitionexception; class<?> gettype(string name) throws nosuchbeandefinitionexception; string[] getaliases(string name); }
2、factorybean
一般情况下,spring通过反射机制利用
spring为此提供了一个org.springframework.bean.factory.factorybean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。bean 为什么默认单例?推荐看下。关注微信公众号:java技术栈,在后台回复:spring,可以获取我整理的 n 篇 spring 教程,都是干货。 factorybean接口对于spring框架来说占用重要的地位,spring自身就提供了70多个factorybean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。 从spring3.0开始,factorybean开始支持泛型,即接口声明改为factorybean
例如自己实现一个factorybean,功能:用来代理一个对象,对该对象的所有方法做一个拦截,在调用前后都输出一行log,模仿proxyfactorybean的功能。 xml-bean配置如下 junit test class factorybean是一个接口,当在ioc容器中的bean实现了factorybean后,通过getbean(string beanname)获取到的bean对象并不是factorybean的实现类对象,而是这个实现类中的getobject()方法返回的对象。要想获取factorybean的实现类,就要getbean(&beanname),在beanname之前加上&。 在该接口中还定义了以下3个方法: tgetobject():返回由factorybean创建的bean实例,如果issingleton()返回true,则该实例会放到spring容器中单实例缓存池中; booleanissingleton():返回由factorybean创建的bean实例的作用域是singleton还是prototype; class
当配置文件中
如果用factorybean的方式实现就灵活点,下例通过逗号分割符的方式一次性的为car的所有属性指定配置值: 有了这个carfactorybean后,就可以在配置文件中使用下面这种自定义的配置方式配置carbean了: 当调用getbean("car")时,spring通过反射机制发现carfactorybean实现了factorybean的接口,这时spring容器就调用接口方法carfactorybean#getobject()方法返回。 如果希望获取carfactorybean的实例,则需要在使用getbean(beanname)方法时在beanname前显示的加上"&"前缀:如getbean("&car"); 下面是一个应用factorybean的例子 factorybean的实现类 普通的bean 测试类 输出的结果: 从结果上可以看到当从ioc容器中获取factorybeanpojo对象的时候,用getbean(string beanname)获取的确是student对象,可以看到在factorybeanpojo中的type属性设置为student的时候,会在getobject()方法中返回student对象。 所以说从ioc容器获取实现了factorybean的实现类时,返回的却是实现类中的getobject方法返回的对象,要想获取factorybean的实现类,得在getbean(string beanname)中的beanname之前加上&,写成getbean(string &beanname)。 作者:至尊宝 推荐去我的博客阅读更多: 2.spring mvc、spring boot、spring cloud 系列教程 3.maven、git、eclipse、intellij idea 系列工具教程 生活很美好,明天见~/**
* my factory bean<p>
* 代理一个类,拦截该类的所有方法,在方法的调用前后进行日志的输出
* @author daniel.zhao
*
*/
public class myfactorybean implements factorybean<object>, initializingbean, disposablebean {
private static final logger logger = loggerfactory.getlogger(myfactorybean.class);
private string interfacename;
private object target;
private object proxyobj;
@override
public void destroy() throws exception {
logger.debug("destroy......");
}
@override
public void afterpropertiesset() throws exception {
proxyobj = proxy.newproxyinstance(
this.getclass().getclassloader(),
new class[] { class.forname(interfacename) },
new invocationhandler() {
@override
public object invoke(object proxy, method method, object[] args) throws throwable {
logger.debug("invoke method......" + method.getname());
logger.debug("invoke method before......" + system.currenttimemillis());
object result = method.invoke(target, args);
logger.debug("invoke method after......" + system.currenttimemillis());
return result; }
});
logger.debug("afterpropertiesset......");
}
@override
public object getobject() throws exception {
logger.debug("getobject......");
return proxyobj;
}
@override
public class<?> getobjecttype() {
return proxyobj == null ? object.class : proxyobj.getclass();
}
@override
public boolean issingleton() {
return true;
}
public string getinterfacename() {
return interfacename;
}
public void setinterfacename(string interfacename) {
this.interfacename = interfacename;
}
public object gettarget() {
return target;
}
public void settarget(object target) {
this.target = target;
}
public object getproxyobj() {
return proxyobj;
}
public void setproxyobj(object proxyobj) {
this.proxyobj = proxyobj;
}
}
<bean id="fbhelloworldservice" class="com.ebao.xxx.myfactorybean">
<property name="interfacename" value="com.ebao.xxx.helloworldservice" />
<property name="target" ref="helloworldservice" />
</bean>
@runwith(junit4classrunner.class)
@contextconfiguration(classes = { myfactorybeanconfig.class })
public class myfactorybeantest {
@autowired
private applicationcontext context;
/**
* 测试验证factorybean原理,代理一个servcie在调用其方法的前后,打印日志亦可作其他处理
* 从applicationcontext中获取自定义的factorybean
* context.getbean(string beanname) ---> 最终获取到的object是factorybean.getobejct(),
* 使用proxy.newinstance生成service的代理类
*/
@test
public void testfactorybean() {
helloworldservice helloworldservice = (helloworldservice) context.getbean("fbhelloworldservice");
helloworldservice.getbeanname();
helloworldservice.sayhello();
}
}
package org.springframework.beans.factory;
public interface factorybean<t> {
t getobject() throws exception;
class<?> getobjecttype();
boolean issingleton();
}
package com.baobaotao.factorybean;
public class car {
private int maxspeed ;
private string brand ;
private double price ;
public int getmaxspeed () {
return this . maxspeed ;
}
public void setmaxspeed ( int maxspeed ) {
this . maxspeed = maxspeed;
}
public string getbrand () {
return this . brand ;
}
public void setbrand ( string brand ) {
this . brand = brand;
}
public double getprice () {
return this . price ;
}
public void setprice ( double price ) {
this . price = price;
}
}
package com.baobaotao.factorybean;
import org.springframework.beans.factory.factorybean;
public class carfactorybean implements factorybean<car> {
private string carinfo ;
public car getobject () throws exception {
car car = new car () ;
string [] infos = carinfo .split ( "," ) ;
car.setbrand ( infos [ 0 ]) ;
car.setmaxspeed ( integer. valueof ( infos [ 1 ])) ;
car.setprice ( double. valueof ( infos [ 2 ])) ;
return car;
}
public class<car> getobjecttype () {
return car. class;
}
public boolean issingleton () {
return false ;
}
public string getcarinfo () {
return this . carinfo ;
}
// 接受逗号分割符设置属性信息
public void setcarinfo ( string carinfo ) {
this . carinfo = carinfo;
}
}
<bean d="car"class="com.baobaotao.factorybean.carfactorybean"
p:carinfo="法拉利,400,2000000"/>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="student" class="com.spring.bean.student">
<property name="name" value="zhangsan" />
</bean>
<bean id="school" class="com.spring.bean.school">
</bean>
<bean id="factorybeanpojo" class="com.spring.bean.factorybeanpojo">
<property name="type" value="student" />
</bean>
</beans>
import org.springframework.beans.factory.factorybean;
/**
* @author 作者 wangbiao
* @parameter
* @return
*/
public class factorybeanpojo implements factorybean{
private string type;
@override
public object getobject() throws exception {
if("student".equals(type)){
return new student();
}else{
return new school();
}
}
@override
public class getobjecttype() {
return school.class;
}
@override
public boolean issingleton() {
return true;
}
public string gettype() {
return type;
}
public void settype(string type) {
this.type = type;
}
}
/**
* @author 作者 wangbiao
* @parameter
* @return
*/
public class school {
private string schoolname;
private string address;
private int studentnumber;
public string getschoolname() {
return schoolname;
}
public void setschoolname(string schoolname) {
this.schoolname = schoolname;
}
public string getaddress() {
return address;
}
public void setaddress(string address) {
this.address = address;
}
public int getstudentnumber() {
return studentnumber;
}
public void setstudentnumber(int studentnumber) {
this.studentnumber = studentnumber;
}
@override
public string tostring() {
return "school [schoolname=" + schoolname + ", address=" + address
+ ", studentnumber=" + studentnumber + "]";
}
}
import org.springframework.context.support.classpathxmlapplicationcontext;
import com.spring.bean.factorybeanpojo;
/**
* @author 作者 wangbiao
* @parameter
* @return
*/
public class factorybeantest {
public static void main(string[] args){
string url = "com/spring/config/beanconfig.xml";
classpathxmlapplicationcontext cpxa = new classpathxmlapplicationcontext(url);
object school= cpxa.getbean("factorybeanpojo");
factorybeanpojo factorybeanpojo= (factorybeanpojo) cpxa.getbean("&factorybeanpojo");
system.out.println(school.getclass().getname());
system.out.println(factorybeanpojo.getclass().getname());
}
}
十一月 16, 2016 10:28:24 上午 org.springframework.context.support.abstractapplicationcontext preparerefresh
info: refreshing org.springframework.context.support.classpathxmlapplicationcontext@1e8ee5c0: startup date [wed nov 16 10:28:24 cst 2016]; root of context hierarchy
十一月 16, 2016 10:28:24 上午 org.springframework.beans.factory.xml.xmlbeandefinitionreader loadbeandefinitions
info: loading xml bean definitions from class path resource [com/spring/config/beanconfig.xml]
十一月 16, 2016 10:28:24 上午 org.springframework.beans.factory.support.defaultlistablebeanfactory preinstantiatesingletons
info: pre-instantiating singletons in org.springframework.beans.factory.support.defaultlistablebeanfactory@35b793ee: defining beans [student,school,factorybeanpojo]; root of factory hierarchy
com.spring.bean.student
com.spring.bean.factorybeanpojo
参考
上一篇: 恕我直言,我怀疑你并不会生成随机数
下一篇: C 实战练习题目3