Spring源码分析系列——bean创建过程分析(四)——实现FactoryBean接口创建bean

spring创建bean的方式

  1. 构造方法

    1. 无参构造方法
    2. 有参构造方法
  2. 工厂方法

    1. 静态工厂方法
    2. 实例工厂方法
  3. 实现FactoryBean接口

    前三篇《Spring源码分析系列——bean创建过程分析(一)——默认无参构造方法创建bean》《Spring源码分析系列——bean创建过程分析(二)——有参构造方法创建bean》《Spring源码分析系列——bean创建过程分析(三)——工厂方法创建bean》介绍了构造方法、工厂方法创建bean的主要流程,本篇分析一下实现FactoryBean接口方式创建bean

测试代码准备

xml配置如下

<?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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

	<bean name="boyService2" class="yxf.instantiate.BoyFactoryBean">
	</bean>
</beans>

实体类如下

public class Lad implements Boy {
    private String name;
    
    public Lad(String name) {
        this.name = name;
    }
    

    @Override
    public void play() {
       System.out.println("I want to play game!");
    }
   
    
}


public interface Boy {    
    void play();
}

实现FactoryBean接口类


//普通FactoryBean
public class BoyFactoryBean implements FactoryBean {

	@Override
	public Boy getObject() throws Exception {
		return new Lad("niulang");
	}

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

}

//实现SmartFactoryBean,并且重写isEagerInit()方法,返回true,会在容器加载就创建单例bean,急加载
public class BoyFactoryBean implements SmartFactoryBean {

	@Override
	public Boy getObject() throws Exception {
		return new Lad("niulang");
	}

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

	@Override
	public boolean isEagerInit() {
		return true;
	}

}

运行测试代码

public class MyXmlConfig {
    public static void main(String[] args) throws Exception {
        ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
       
        Lad lad = (Lad) ac.getBean("boyService2");
        System.out.println(lad);
    }
}

preInstantiateSingletons()方法分析

在经过AbstractApplicationContext的refresh()方法后,会调用DefaultListableBeanFactory的perInstantiateSingletons()方法,这个方法会在容器初始化后就实例化所有的单例bean。

看一下精简后的源码

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

		//注册bean定义的名称集合
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// 初始化所有非懒加载的单例bean
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				//如果实现了FactoryBean接口,走这个创建bean
				if (isFactoryBean(beanName)) {
					//调用getBean方法,实例化实现了FactoryBean接口的类,FACTORY_BEAN_PREFIX = “&”
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						//如果具体实现的是SmartFactoryBean,且重写了isEagerInit()方法返回值true,则提前实例化bean
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				//非FactoryBean,普通getBean()创建bean
				else {
					getBean(beanName);
				}
			}
		}

		
	}

通过以上源码及注释,我们可以得到,在容器初始化后,就会实例化所有FactoryBean。并且如果具体实现的是SmartFactoryBean,且同时重写了isEagerInit()方法,返回值为true,则会实例化具体bean。

getBean(FACTORY_BEAN_PREFIX + beanName)创建FactoryBean分析

FACTORY_BEAN_PREFIX 是一个"&"符号
在doGetBean()方法会将它去掉
看一下部分源码

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

		String beanName = transformedBeanName(name);
}

会通过transformedBeanName()方法将name转换为beanName,
再来看一下这个方法

protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

再看BeanFactoryUtils.transformedBeanName(name)方法

public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		//如果不是“&”开头,直接返回
		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
			return name;
		}
		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
			do {
				//去掉"&"并返回真实的beanName
				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
			}
			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
			return beanName;
		});
	}

可以确定创建的factoryBean的beanName是实际bean的beanName。
再看下doGetBean()方法创建单例bean的代码

if (mbd.isSingleton()) {
	sharedInstance = getSingleton(beanName, () -> {
		try {
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {			
			destroySingleton(beanName);
			throw ex;
		}
	});
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

是通过getSingleton()方法。看一下代码

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 {
					//关键代码,这个就是执行的createBeab()方法
					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) {
					//将新创建的单例bean放入单例池
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

getSingleton()方法会将创建完的单例bean放入单例池,通过addSingleton()方法,来看一下代码

protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			//放入单例池,这里的beanName就是实际的beanName,没有带“&”
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

getBean(beanName)分析,创建实际bean

上一步已经将beanName及创建的factoryBean放入单例池了,所以会直接从单例池中取,不过如果直接取只能得到factoryBean,而不是实际bean。实际bean还没有创建,我们来看下怎么从factoryBean转换到真实bean。

看一下doGetBean()方法

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

		String beanName = transformedBeanName(name);
		Object bean;

		// 先从单例池中取
		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 + "'");
				}
			}
			//将factoryBean转换为真实bean
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
	}

因为之前已经在单例池中放入了key为beanName,value为factoryBean的新创建的工厂bean,此时就可以通过通过getSingleton(beanName)获取了,只不过获取的是factoryBean。
看一下getSingleton(beanName)方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//从单例池singletonObjects中取
		Object singletonObject = this.singletonObjects.get(beanName);
		
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

重头戏是getObjectForBeanInstance()方法。这个方法把factoryBean转换为真实bean。这个方法经过一系列步骤最终会调用doGetObjectFromFactoryBean()方法。来看一下这个方法,
精简代码之后,如下

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
		Object object;
		try {
				object = factory.getObject();
			}
		}
		

		return object;
	}

就是调用了factory的getObject()方法,然后将返回值返回去,而我们使用FactoryBean接口就是重写了getObject()方法,new出来我们真实的类,所以一切都明了啦!

总结

  1. 实现FactoryBean接口,重写getObject()方法,可以实现创建bean。稍微深入一点,如果具体实现SmartFactoryBean接口,并且同时重写了isEagerInit()方法,返回值设置为true,则可以在容器初始化时直接实例化单例bean,否则就是懒加载。
  2. 具体的实现过程是,在容器初始化的时候,先将factoryBean实例化,并且以真实的beanName为key放入单例池。调用的是getBean("&"+beanName)方法,获取的是factoryBean。
  3. 再调用getBean(beanName)方法,会从单例池中取到factoryBean,再将factoryBean转换为真实bean。具体是通过调用factoryBean的getObject()方法。这样就首尾呼应了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值