Loading

BeanFactory和FactoryBean的区别:

用了这么久的SpringMVC框架,有一天看到一个问题,BeanFactory和FactoryBean有什么区别?

我当时的第一想法是BeanFactory不就是生产bean的工厂吗,FactoryBean不就是工厂里面生产出来的Bean吗?

后来发现,我的答案不是很对。去查了Spring的源码,看到了FactoryBean的接口,如下

public interface FactoryBean<T> {

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
	@Nullable
	T getObject() throws Exception;
	@Nullable
	Class<?> getObjectType();
	default boolean isSingleton() {
		return true;
	}
}

从开始的注释第一句就是,FactoryBean是BeanFactory里面使用到的接口。真的是在BeanFactory使用到的bean。同时实现了这个接口的bean不能向常规的bean一样使用他,如何注入一个FactoryBean后面的例子会提到。

但是FactoryBean实际上还是一个工厂,他有一个泛型T,表示这个工厂创建的实例类型,getObject() 则是返回T,就是创建bean的方法。getObjectType返回的是创建bean的Class对象。而isSingleton则是表示一个FactoryBean创建出来的Bean是不是单例,

这个应该不难理解。

那么如何在实际开发里面使用呢?

这里有两个对象,一个是要创建出来的泛型T,一个是实现FactoryBean接口的类。

类:ToolFactoryBean

public class ToolFactoryBean implements FactoryBean<Tool> {
	private int factoryId;
	private int toolId;

	public void setFactoryId(int factoryId) {
		this.factoryId = factoryId;
	}

	public int getToolId() {
		return toolId;
	}

	public void setToolId(int toolId) {
		this.toolId = toolId;
	}

	@Override
	public Tool getObject() throws Exception {
		return new Tool(toolId);
	}

	@Override
	public Class<?> getObjectType() {
		return Tool.class;
	}

	public int getFactoryId() {
		return factoryId;
	}
}

需要注意的是如果你用的是xml配置方式,那么你需要有setter来设置属性。

被创建出来的实例:

public class Tool {
	private int id;
	public Tool(int i) {
		this.id = i;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
}

这里只是实现功能不需要定义复杂的属性。只需要定义一个id即可。

配置类:

@Configuration
public class FactoryBeanAppConfig {
	@Bean(name = "toolFactory")
	public ToolFactoryBean getTooFactoryBean() {
		ToolFactoryBean toolFactoryBean = new ToolFactoryBean();
		toolFactoryBean.setFactoryId(1111);
		toolFactoryBean.setToolId(2333);
		return toolFactoryBean;
	}

//	@Bean
//	public Tool getTool() throws Exception {
//		return getTooFactoryBean().getObject();
//	}
}

xml配置方式多少有点落伍了,这里直接使用配置类的方式。需要说明的是如果配置了ToolFactoryBean就无需再配置出他创建出来的那个bean了,因为spring会糊涂。

使用方式:

package com.example.springmvcdemo.bean;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = FactoryBeanAppConfig.class)
public class ToolFactoryBeanTest1 {
	@Autowired
	private Tool tool;

	@Resource(name = "&toolFactory")
	private ToolFactoryBean toolFactoryBean;

	@Test
	public void test() {
		assertThat(tool.getId(), equalTo(2333));
		assertThat(toolFactoryBean.getFactoryId(), equalTo(1111));
	}

}

由于FactoryBean无法通过正常的AutoWired获取到,所以使用& + beanName的方式获取,同样的,你会发现没有配置的Toolbean居然可以直接Autowired

以上就是FactoryBean的简单的使用,可以看出,FactoryBean可以给我们留有一些预设Bean属性的余地。

FactoryBean是如何在BeanFactory里面生效的?

  1. FactoryBean的创建时机

因为是测试所以前面有分析依赖,然后走到了注入创建bean的逻辑。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					singletonObject = singletonFactory.getObject(); 
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

核心的代码是:

singletonObject = singletonFactory.getObject(); 

用来创建一个FactoryBean

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();// 创建bean
		Class<?> beanType = instanceWrapper.getWrappedClass();
		//省略一些代码

		return exposedObject;
	}
```java

FactoryBean里面创建的Bean将在`getObjectForBeanInstance`方法中创建:

```java
protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		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;
			}
			return beanInstance;
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

其实最终调用的都是FactoryBean的getObject方法来创建Bean

那么BeanFactory又是什么呢?

源代码长了,截取部分注释和方法分析

开篇第一句:

The root interface for accessing a Spring bean container. //所有Spring容器的父接口

他的增强的接口有ListableBeanFactory, ConfigurableBeanFactory,他提供了一系列的获取Bean的方法:

Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;

获取Bean信息的一些方法

boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);

另外提供了ObjectProvider的获取方法:

<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

ObjectProvider是用来做延迟加载的,可以消除@Autowired

例子:

public class FooService {
    private final FooRepository repository;
    public FooService(ObjectProvider<FooRepository> repositoryProvider) {
        this.repository = repositoryProvider.getIfUnique();
    }
}

另外在BeanFactory中还有,如何获取FactoryBean的方法:

	/**
	 * 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和Bean信息的各种方法,而FactoryBean是在BeanFactory里面使用的一种特殊的Bean,他主要的职能是用来创建Bean。

参考:

  1. https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/ObjectProvider.html
  2. https://www.baeldung.com/spring-factorybean
  3. https://blog.csdn.net/alex_xfboy/article/details/83342164?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-2&spm=1001.2101.3001.4242
posted @ 2020-12-24 22:18  lijuny  阅读(183)  评论(0)    收藏  举报