BeanFactory和FactoryBean到底有什么区别?

1.1 BeanFactory和FactoryBean之间的关系

两者之间有什么关系,按我的理解,两者并没有什么必然的联系。FactoryBean也是一种Bean,也是通过BeanFactory容器获取。

BeanFactory:The root interface for accessing a Spring bean container.This is the basic client view of a bean container.什么意思?访问bean 容器的根接口,触摸到bean容器的基本客户端。很多接口和类都实现或者继承该接口,比如常用的ApplicationContext、FileSystemXmlApplicationContext、ClassPathXmlApplicationContext、AnnotationConfigApplicationContext等等。这个接口提供了我们对容器的实例化对象的获取。请看代码:
一般我们不用原始接口BeanFactory,功能较少。我们可以使用ApplicationContext接口,它封装了国际化等相关的信息,比较全面。

ApplicationContext context = new AnnotationConfigApplicationContext(AopProxyConfig.class);
AopCity city = (AopCity) context.getBean("aopCity");

FactoryBean<T>:Interface to be implemented by objects used within a {@link BeanFactory} which are themselves factories for individual objects. If a bean implements this interface, it is used as a factory for an object to expose, not directly as a bean instance that will be exposed itself.
FactoryBean接口由BeanFactory中使用的对象实现,这些对象本身是各个对象的工厂。如果一个bean实现了这个接口,那么它将被用作要公开的对象的工厂,而不是直接用作将自己公开的bean实例。简单点就是,通过FactoryBean对原始Bean做了一层封装,通过context .getBean(“dbFactoryBean”)获取的对象已经被我处理了。直接上代码:

自定义FactoryBean

public class DbFactoryBean implements FactoryBean<FactoryBeanUser> {

	private static final Logger logger = LoggerFactory.getLogger(DbFactoryBean.class);

	@Override
	public FactoryBeanUser getObject() throws Exception {
		logger.debug("DbFactoryBean执行...");
		FactoryBeanUser user = new FactoryBeanUser();
		user.setUserName("张三");
		return user;
	}

	@Override
	public Class<?> getObjectType() {
		return null;
	}

	public void printObject(){
		logger.debug("DbFactoryBean is {}",this);
	}
}

配置类

@Configuration
public class FactoryBeanConfig {
	//FactoryBean
	@Bean
	public DbFactoryBean dbFactoryBean(){
		return new DbFactoryBean();
	}
	//原始对象
	@Bean
	public FactoryBeanUser factoryBeanUser(){
		return new FactoryBeanUser();
	}
}

测试类

@Test
public void testFactoryBean(){
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FactoryBeanConfig.class);
		//通过获取FactoryBean对象我们获取到的是FactoryBeanUser实例
		FactoryBeanUser factoryBeanUser = (FactoryBeanUser) context.getBean("dbFactoryBean");
		logger.debug("test user name is {}",factoryBeanUser.getUserName());
		//如果想要获取DbFactoryBean 我们可以通过增加“&”标识符获取
		DbFactoryBean dbFactoryBean = (DbFactoryBean) context.getBean("&dbFactoryBean");
		dbFactoryBean.printObject();
		//这个就是获取原始FactoryBeanUser对象,没有经过FactoryBean处理
		FactoryBeanUser factoryBeanUser1 = (FactoryBeanUser)context.getBean("factoryBeanUser");
		logger.debug("test user name is {}",factoryBeanUser1.getUserName());
	}

结果:

09:40:14.187 [main] DEBUG org.my.study.factorybean.DbFactoryBean - DbFactoryBean执行...
09:40:14.190 [main] DEBUG org.my.study.aop.ConfigTest - test user name is 张三
09:40:14.195 [main] DEBUG org.my.study.factorybean.DbFactoryBean - DbFactoryBean is org.my.study.factorybean.DbFactoryBean@33617539
09:40:14.195 [main] DEBUG org.my.study.aop.ConfigTest - test user name is null

通过结果我们可以看出FactoryBean的作用,他可以改变一些Bean,实现Bean初始化相关的一些操作。

1.2 看一看BeanFactory和FactoryBean源码

BeanFactory

首先看看BeanFactory的源码,其实是没啥看的,很多类实现BeanFactory接口。直接看AnnotationConfigApplicationContext,怎么实例化一个Bean工厂的。首先根据我们上边说的测试类里的代码进入AnnotationConfigApplicationContext

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
	this();
	register(componentClasses);
	refresh();
}

紧接着进入this()方法

public AnnotationConfigApplicationContext() {
	this.reader = new AnnotatedBeanDefinitionReader(this);
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

我们知道调用构造方法肯定会先初始化父类构造方法,所以会调用父类GenericApplicationContext的构造方法,我们可以看初始化了一个DefaultListableBeanFactory对象,我们的Bean工厂也就初始化成功了。

public GenericApplicationContext() {
	this.beanFactory = new DefaultListableBeanFactory();
}

在这里插入图片描述
我们可以看到通过getBean方法我们就可以获取到beanFactory 里的实例。访问bean 容器的根接口,也就是我们可以通过实现类去容器里取我们想要的实例对象。

FactoryBean

我们再看看FactoryBean源码,他其实就是一个Bean,我们看下是怎么通过实现FactoryBean接口就可以获取到包装之后的Bean的。首先我们还是进入这块代码

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
	this();
	register(componentClasses);
	refresh();
}

然后紧接着进入refresh()代码里,然后进入finishBeanFactoryInitialization(beanFactory)方法进入下面这个

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

我们看下这个方法里的源码

@Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				//判断是否是FactoryBean
				if (isFactoryBean(beanName)) {
					//FACTORY_BEAN_PREFIX 值是 “&”
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					getBean(beanName);
				}
			}
		}
		//省略部分源码
	}

然后进入getBean()创建实例化Bean。

当通过FactoryBeanUser factoryBeanUser = (FactoryBeanUser) context.getBean(“dbFactoryBean”);获取对象时我们进入getBean()源码里去看最终会进入AbstractBeanFactory类doGetBean方法

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		//从缓存里获取实例化DbFactoryBean
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			//最终进入此方法我们可以看到传入name和beanName两个参数。如果传入name带有“&”
			//此时会做处理
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

接着我们继续往下看,进入getObjectForBeanInstance方法,进入到AbstractAutowireCapableBeanFactory类中getObjectForBeanInstance方法。

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

		String currentlyCreatedBean = this.currentlyCreatedBean.get();
		if (currentlyCreatedBean != null) {
			registerDependentBean(beanName, currentlyCreatedBean);
		}
		//
		return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
	}

调用父类的getObjectForBeanInstance方法,我们可以看到会将我们调用context.getBean(“dbFactoryBean”)里的name,和处理后的beanName都传入,

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.
		//此处会判断name是否带有“&”,如果带有就会进入此方法,返回FactoryBean实例。
		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) {
			//如果不带有“&”,会进入此处然后调用getObjectFromFactoryBean获取bean
			// 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;
	}
	
public static boolean isFactoryDereference(@Nullable String name) {
		return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
	}

接下来我们可以看下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) {
					//代码执行会进入此处
					object = doGetObjectFromFactoryBean(factory, beanName);
					//省略部分代码
}

然后进入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((PrivilegedExceptionAction<Object>) factory::getObject, acc);
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				//此时就会调用getObject()方法
				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);
		}

		// Do not accept a null value for a FactoryBean that's not fully
		// initialized yet: Many FactoryBeans just return null then.
		if (object == null) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(
						beanName, "FactoryBean which is currently in creation returned null from getObject");
			}
			object = new NullBean();
		}
		return object;
	}

记不记得我们自定义的FactoryBean里实现的getObject方法。这时就会调用此方法,然后生成返回我们创建的对象,也就是FactoryBeanUser 。如果加上“&”符号,我们就会直接返回我们实现的FactoryBean对象,也就是DbFactoryBean。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值