【spring源码系列】之【FactoryBean类型的接口】

博客 分享
0 185
张三
张三 2022-06-12 23:00:26
悬赏:0 积分 收藏

【spring源码系列】之【FactoryBean类型的接口】

1.概述

目前我们知道,spring创建bean有多种方式,比如xml方式创建,比如@Component,@Service,@Controler,@Repository注解创建,比如@Autowired依赖注入创建,后续还有通过springboot方式的配置注解@Configuration与@Bean方式结合创建,这里不一一介绍,等分析spring boot源码的时候再做总结。

就spring本身,提供了一种接口方式创建bean,就是本节要讨论的通过FactoryBean接口方式创建。

2.实例

FactoryBean接口的实现类FactoryBeanDemo:

package com.wzj.FactoryBean;import org.springframework.beans.factory.FactoryBean;import org.springframework.stereotype.Service;@Servicepublic class FactoryBeanDemo implements FactoryBean {    @Override    public Object getObject() throws Exception {        return new FactoryB();    }    @Override    public Class<?> getObjectType() {        return FactoryB.class;    }}

通过FactoryBean实现类,完成自定义类FactoryB的实例化,FactoryB:

package com.wzj.FactoryBean;import lombok.Data;@Datapublic class FactoryB {    private String name = "wzj";}

测试类:

public class TestSpring {    @Autowired    private ApplicationContext applicationContext;    @Test    public void testFactoryBean() {        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");        FactoryB factoryB = (FactoryB)applicationContext.getBean("factoryBeanDemo");        System.out.println(factoryB);        FactoryBeanDemo factoryBeanDemo = (FactoryBeanDemo)applicationContext.getBean("&factoryBeanDemo");        System.out.println(factoryBeanDemo);    }

测试结果:

可以看出,当获取名称为factoryBeanDemo的实例时,得到的是getObject()方法里创建的FactoryB类型的对象,而获取加前缀&factoryBeanDemo的实例时,得到的是FactoryBeanDemo本身的实例。

3.源码

step1: FactoryBean 接口的调用入口在实例化和 IOC/DI 做完后,就会调用 FactoryBean 类型的接口如下图所示

				// Create bean instance.				// 创建bean实例				if (mbd.isSingleton()) {					sharedInstance = getSingleton(beanName, () -> {						try {							return createBean(beanName, mbd, args);						}						catch (BeansException ex) {							// Explicitly remove instance from singleton cache: It might have been put there							// eagerly by the creation process, to allow for circular reference resolution.							// Also remove any beans that received a temporary reference to the bean.							destroySingleton(beanName);							throw ex;						}					});					// FactoryBean的调用入口					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);				}

step2: 如果要获取到 FactoryBean 类本身,就必须加上&符号,比如 beanFactory.getBean("&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不为空,且以前缀&打头,直接返回bean本身		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;		}		
	public static boolean isFactoryDereference(@Nullable String name) {		return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));	}
	String FACTORY_BEAN_PREFIX = "&";

stet3: BeanFactory.getBean("beanName")只能获取到 getObject()方法返回的实例。getObject 方法返回的实例会有单独的缓存存储,跟其他实例不是同一个缓存,对应的缓存是:factoryBeanObjectCache

                // 如果是不是以前缀&打头,并且是FactoryBean类型的		Object object = null;		if (mbd != null) {			mbd.isFactoryBean = true;		}		else {			// 从缓存里拿FactoryBean实例			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;	}
	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {		if (factory.isSingleton() && containsSingleton(beanName)) {			synchronized (getSingletonMutex()) {				// 先从缓存factoryBeanObjectCache取				Object object = this.factoryBeanObjectCache.get(beanName);				// 如果缓存为空,				if (object == null) {					// 调用getObject方法					object = doGetObjectFromFactoryBean(factory, beanName);					// Only post-process and store if not put there already during getObject() call above					// (e.g. because of circular reference processing triggered by custom getBean calls)					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);					if (alreadyThere != null) {						object = alreadyThere;					}					else {						if (shouldPostProcess) {							if (isSingletonCurrentlyInCreation(beanName)) {								// Temporarily return non-post-processed object, not storing it yet..								return object;							}							beforeSingletonCreation(beanName);							try {								object = postProcessObjectFromFactoryBean(object, beanName);							}							catch (Throwable ex) {								throw new BeanCreationException(beanName,										"Post-processing of FactoryBean's singleton object failed", ex);							}							finally {								afterSingletonCreation(beanName);							}						}						if (containsSingleton(beanName)) {							// 最后放到缓存中							this.factoryBeanObjectCache.put(beanName, object);						}					}				}				return object;			}		}                ......

小结:具体代码参考 getSingleton 方法之后 getObjectForBeanInstance

  • 如果bean实例不是 FactoryBean 类型的或者 name 以&开始的则直接返回实例。
  • 如果bean是 FacotyBean 并且不是以&开头, 会通过方法doGetObjectFromFactoryBean 调用FactoryBean 内部继承实现的 getObject 方法,并且判断一级缓存中如果存在该 bean 实例把实例缓存到factoryBeanObjectCache 对应的 map 中,这个是单独缓存 FactoryBean 类型实例的 map。

4.总结

灵活创建所需实例对象的时候,通过实现FactoryBean接口的getObject方法定义实例化过程。

比如MyBatis提供mybatis-spring项目中的 org.mybatis.spring.SqlSessionFactoryBean

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {	// ...省略其他代码		public SqlSessionFactory getObject() throws Exception {	if (this.sqlSessionFactory == null) {	  afterPropertiesSet();	}	return this.sqlSessionFactory;	}}

sqlSessionFactory是SqlSessionFactoryBean的一个属性,它的赋值是在通过回调afterPropertiesSet()方法进行的。 因为SqlSessionFactoryBean实现了InitializingBean接口,所以在Spring初始化Bean的时候,能回调afterPropertiesSet()方法。

public void afterPropertiesSet() throws Exception {    // buildSqlSessionFactory()方法会根据mybatis的配置进行初始化。	this.sqlSessionFactory = buildSqlSessionFactory();}

在上面的afterPropertiesSet()方法中,buildSqlSessionFactory()方法会根据mybatis的配置,完成客户所需要的的sessionFactory的初始化。

posted @ 2022-06-12 22:00 小猪爸爸 阅读(13) 评论(0) 编辑 收藏 举报
回帖
    张三

    张三 (王者 段位)

    821 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员