理解spring中的BeanFactory和FactoryBean的区别与联系
https://blog.csdn.net/joenqc/article/details/66479154
https://blog.csdn.net/wangbiao007/article/details/53183764
首先,这俩都是个接口…
实现 BeanFactory 接口的类表明此类事一个工厂,作用就是配置、新建、管理 各种Bean。
而 实现 FactoryBean 的类表明此类也是一个Bean,类型为工厂Bean(Spring中共有两种bean,一种为普通bean,另一种则为工厂bean)。顾名思义,它也是用来管理Bean的,而它本身由spring管理。
一个Bean想要实现 FactoryBean ,必须实现以下三个接口:
1. Object getObject():返回由FactoryBean创建的Bean的实例
2. boolean isSingleton():确定由FactoryBean创建的Bean的作用域是singleton还是prototype;
3. getObjectType():返回FactoryBean创建的Bean的类型。
有一点需要注意,如果将一个实现了FactoryBean的类成功配置到了spring上下文中,那么通过该类对象的名称(比如appleFactoryBean)从spring的applicationContext或者beanFactory获取bean时,获取到的是appleFactoryBean创建的apple实例,而不是appleFactoryBean自己,如果想通过spring拿到appleFactoryBean,需要在名称前加 & 符号 :
out.println(applicationContext.getBean("&appleFactoryBean"))
- 1
这个prefix在BeanFactory接口源码中有提到:
/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from
* beans <i>created</i> by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
*/
String FACTORY_BEAN_PREFIX = "&";
还有一点需要注意,FactoryBean管理的bean实际上也是由spring进行配置、实例化、管理,因此由FactoryBean管理的bean不能再次配置到spring配置文件中(xml、java类配置、注解均不可以),否则会报如下异常:
Exception in thread "main" org.springframework.beans.factory.BeanIsNotAFactoryException: Bean named 'appleFactoryBean' is expected to be of type 'org.springframework.beans.factory.FactoryBean' but was actually of type 'java.lang.Object'
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:742)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
at com.joen.testspringcontainer.Start.main(Start.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
附上一个例子:
spring配置类:
@Configuration
@ComponentScan
public class Configurations {
}
AppleBean :
//@Component 这里不可以加注解 !!!!!!
public class AppleBean{
}
AppleFactoryBean :
@Component
public class AppleFactoryBean implements FactoryBean{
public Object getObject() throws Exception {
return new AppleBean();
}
public Class<?> getObjectType() {
return AppleBean.class;
}
public boolean isSingleton() {
return false;
}
}
启动类 :
public class Start {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Configurations.class);
out.println(applicationContext.getBean("appleFactoryBean"));//得到的是apple
out.println(applicationContext.getBean("&appleFactoryBean"));//得到的是apple工厂
}
}
1.BeanFactory
BeanFactory是IOC最基本的容器,负责生产和管理bean,它为其他具体的IOC容器提供了最基本的规范,例如DefaultListableBeanFactory,
XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。
BeanFactory源码
-
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
FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。
FactoryBean源码
-
package org.springframework.beans.factory; -
public interface FactoryBean<T> { -
T getObject() throws Exception; -
Class<?> getObjectType(); -
boolean isSingleton(); -
}
下面是一个应用FactoryBean的例子
-
<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>
FactoryBean的实现类
-
import org.springframework.beans.factory.FactoryBean; -
/** -
* @author 作者 wangbiao -
* @date 创建时间:2016年11月14日 上午11:19:31 -
* @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; -
} -
}
普通的bean
-
/** -
* @author 作者 wangbiao -
* @date 创建时间:2016年11月14日 上午11:13:18 -
* @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 -
* @date 创建时间:2016年11月14日 上午11:11:35 -
* @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
从结果上可以看到当从IOC容器中获取FactoryBeanPojo对象的时候,用getBean(String BeanName)获取的确是Student对象,可以看到在FactoryBeanPojo中的type属性设置为student的时候,会在getObject()方法中返回Student对象。所以说从IOC容器获取实现了FactoryBean的实现类时,返回的却是实现类中的getObject方法返回的对象,要想获取FactoryBean的实现类,得在getBean(String BeanName)中的BeanName之前加上&,写成getBean(String &BeanName)。
3.BeanFactory和FactoryBean的区别
BeanFactory和FactoryBean其实没有什么比较性的,只是两者的名称特别接近,所以有时候会拿出来比较一番,BeanFactory是提供了OC容器最基本的形式,给具体的IOC容器的实现提供了规范,FactoryBean可以说为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类,要想深入准确的理解FactoryBean,只有去读读Spring源码了。
本文详细解析了Spring框架中BeanFactory和FactoryBean的区别与联系,包括它们的定义、实现方式及应用场景,帮助读者更好地理解这两种核心概念。

1716

被折叠的 条评论
为什么被折叠?



