FactoryBean:spring中所有的bean都是由容器来管理的也就是BeanFactory,但是对FactoryBean而言可不是简单的bean,而是一个能产生或者修饰对象生成的工厂Bean,可以用转义字符"&"来得到FactoryBean本身,下面我们来看具体例子:
新建一个类:
package com.ck.bean;
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private String sex;
private Integer age;
public Person() {
System.out.println("constructor");
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
新建一个FactoryBean的实现:
package com.ck.bean;
import org.springframework.beans.factory.FactoryBean;
public class PersonFactoryBean implements FactoryBean<Person> {
@Override
public Person getObject() throws Exception {
Person person = new Person();
person.setId(1l);
return person;
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
我们来看下配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
<bean id="person" class="com.ck.bean.PersonFactoryBean"/>
</beans>
再来看下测试代码:
public class IocTest {
private Log log = LogFactory.getLog(getClass());
private Object person;
private Object factoryBean;
@Test
public void test() {
ConfigurableApplicationContext ctx = new FileSystemXmlApplicationContext( "src/main/resources/applicationContext.xml");
factoryBean = ctx.getBean("&person");
person = ctx.getBean("person");
System.out.println(person.getClass());
System.out.println(factoryBean.getClass());
}
}
测试结果如下:
三月 22, 2019 6:06:11 下午 org.springframework.context.support.FileSystemXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@3c679bde: startup date [Fri Mar 22 18:06:11 CST 2019]; root of context hierarchy
三月 22, 2019 6:06:12 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from file [X:\CK\stsws\springWeb\src\main\resources\applicationContext.xml]
class com.ck.bean.Person
class com.ck.bean.PersonFactoryBean
我们可以清晰的看到加上转义符"&"的是获取FactoryBean本身,否则获取到的是Person类对象.
看完了例子,我们接下来看下FactoryBean在spring中是怎么实现的,先看下FactoryBean的源代码:
public interface FactoryBean<T> {
//获取由FactoryBean创建的对象
T getObject() throws Exception;
//获取由FactoryBean创建Bean的类型
Class<?> getObjectType();
//返回FactoryBean创建Bean是不是单例
boolean isSingleton();
}
下面我们继续看下FactoryBean实现原理:
看下AbstractBeanFactory中:
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 如果不是对FactoryBean的调用,那么结束处理
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//此处方法是从FactoryBean中得到Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
接下来我们看FactoryBeanRegistrySupport中的getObjectFromFactoryBean:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//此处获取bean的地方
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
我们继续看下该类的doGetObjectFromFactoryBean方法:
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//这里调用factory的getObject方法来从FactoryBena中得到Bean
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
}
这里返回的是作为工厂的FactoryBean生产的产品,而不是FactoryBean本身.这种FactoryBean的机制可以为我们提供一个很好的封装机制,比如aop的ProxyFactoryBean或者JndiObjectFactoryBean.