上一篇我们分析了创建bean实例需要的
RootBeanDefinition
定义的构建。今天我们在接着继续讨论,拿到RootBeanDefinition
定义后,如何创建bean实例。但在创建bean实例前还有个很重要的知识点需要提前讲解一下什么是FactoryBean
,因为在创建bean实例的时候很多地方会遇到。
目前Spring创建bean实例都是通过配置指定的class属性,利用反射的方式来创建的,但是在某些情况下,通过配置的方式创建bean实例并不灵活,所以Spring提供了另外一种方式来创建bean实例,就是通过实现FactoryBean
接口,重写其方法,通过调用getObject()
方法来获取bean实例,Spring本身也大量使用这种方式来创建bean实例。接下来我们来具体看下如果使用FactoryBean
创建一个bean实例出来。
实现
FactoryBean
接口,重写其方法,源码如下。
package Service;
import org.springframework.beans.factory.FactoryBean;
import model.Car;
/**
* @author zxz
* 实现FactoryBean接口,重写其方法
*/
public class CarFactoryBean implements FactoryBean<Car> {
/**
* 返回实际的bean实例,该方法会在getBean的时候通过CarFactoryBean对象调用
*
* @return
* @throws Exception
*/
public Car getObject() throws Exception {
return new Car("audi", 300000);
}
/**
* 返回实际的bean对应的class类型
*
* @return
*/
public Class<?> getObjectType() {
return Car.class;
}
/**
* 返回bean实例是否是单例,true:表示目标实例是单例的,会被保存在BeanFactory里面,false:表示目标实例非单例,每次都会创建一个新的目标bean实例出来。
*
* @return
*/
public boolean isSingleton() {
return true;
}
}
package model;
/**
* @author zxz
* 目标实例
*/
public class Car {
private String brand;
private int price;
public Car(String brand, int price) {
this.brand = brand;
this.price = price;
}
将
CarFactoryBean
通过配置的方式注入到BeanFactory
里面,具体配置如下。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="Service.CarFactoryBean"/>
</beans>
测试用例。
import model.Car;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author zxz
*/
public class JuniteTest {
@Test
public void testBeanPostProcessor() {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Car car = (Car) context.getBean("car");
System.out.println("brand: " + car.getBrand() + " , price: " + car.getPrice());
}
}
测试用例比较简单,我们来看下Car实例创建原理是什么样子的吧?回到上一篇文章的
preInstantiateSingletons()
方法。接着看创建完RootBeanDefinition
定义之后的逻辑。
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("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()) {
// 就是这里,判断当前的beanName对应的bean是否是一个FactoryBean。
if (isFactoryBean(beanName)) {
// 如果是一个FactoryBean,则获取对应的FactoryBean实例。
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);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
来看看
isFactoryBean()
是怎么根据beanName判断是否是一个FactoryBean
。
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
// Step1:解析名字,之前的文章分析过,忘记的朋友翻翻原来的文章。
String beanName = transformedBeanName(name);
// Step2:根据beanName从缓存中获取对应的bean实例。这个时候缓存里面肯定没有,所以这里返回空。
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
// Step3:如果缓存能取到则直接返回。
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
// Step4:如果当前BeanFactory不存在对应的BeanDefinition定义 && 获取父BeanFactory并且如果实现了ConfigurableBeanFactory,则从父BeanFactory判断beanName是否是一个FactoryBean。
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
// Step5:根据beanName和RootBeanDefinition判断是否是FactoryBean。
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
// Step1:获取beanName对应的Class类型
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
// Step2:class类型不为null && class类型是通过FactoryBean分配的。则认为是一个FactoryBean,isAssignableFrom()是一个native方法。
return (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
}
接着来看下
beanName
对应的Class类型是如何获取到的,此处调用的AbstractAutowireCapableBeanFactory.predictBeanType()
方法。
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
// Step1:根据beanName和mbd确定目标类型
Class<?> targetType = determineTargetType(beanName, mbd, typesToMatch);
// Apply SmartInstantiationAwareBeanPostProcessors to predict the
// eventual type after a before-instantiation shortcut.
// Step2:如果获取到了对应的class类型 && mbd是合成的 && 存在InstantiationAwareBeanPostProcessors(我们这里没有,所以if条件不成立)
if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// Step2.1:遍历所有的BeanPostProcessor来获取对应的class类型
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Class<?> predicted = ibp.predictBeanType(targetType, beanName);
if (predicted != null && (typesToMatch.length != 1 || FactoryBean.class != typesToMatch[0] ||
FactoryBean.class.isAssignableFrom(predicted))) {
return predicted;
}
}
}
}
// Step3:返回获取到的class类型
return targetType;
}
来看看class类型是怎么被确定下来的。
protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
// Step1:通过mbd(RootBeanDefinition定义)获取class类型。
Class<?> targetType = mbd.getTargetType();
if (targetType == null) {
// Step2:通过mbd指定的factory获取对应的class类型,如果没有指定Factory,则通过resolveBeanClass获取class类型。
targetType = (mbd.getFactoryMethodName() != null ?
getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
resolveBeanClass(mbd, beanName, typesToMatch));
if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
mbd.resolvedTargetType = targetType;
}
}
// Step3:返回class类型。
return targetType;
}
接着来看看如何从
resolveBeanClass()
中获取到class类型。
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
throws CannotLoadBeanClassException {
try {
// Step1:mbd如果指定了class类型,则直接返回该class类型。
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
// Step2:如果有安全检查,优先优先做安全检查,然后通过doResolveBeanClass获取到class类型并返回。
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}
else {
return doResolveBeanClass(mbd, typesToMatch);
}
}
catch (PrivilegedActionException pae) {
ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (ClassNotFoundException ex) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
}
catch (LinkageError err) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
}
}
接着看看
doResolveBeanClass()
的真正实现,FactoryBean
对应的class类型也是从这里确定的。
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
// Step1:获取ClassLoader
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader classLoaderToUse = beanClassLoader;
// Step2:如果指定了要获取class类型,则获取对应的模板classLoader,我们这没有,可以忽略该方法。
if (!ObjectUtils.isEmpty(typesToMatch)) {
// When just doing type checks (i.e. not creating an actual instance yet),
// use the specified temporary class loader (e.g. in a weaving scenario).
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
classLoaderToUse = tempClassLoader;
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
// Step3:获取RootBeanDefinition定义的class名字
String className = mbd.getBeanClassName();
if (className != null) {
// Step3.1:根据类名和mbd计算一个结果用来比较,由于我们测试用例指定的比较简单,所以这里返回的名字肯定和className相同。这个方法执行了一些表达式计算,具体内容可自行了解。
Object evaluated = evaluateBeanDefinitionString(className, mbd);
if (!className.equals(evaluated)) {
// A dynamically resolved expression, supported as of 4.2...
if (evaluated instanceof Class) {
return (Class<?>) evaluated;
}
else if (evaluated instanceof String) {
return ClassUtils.forName((String) evaluated, classLoaderToUse);
}
else {
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
}
}
// When resolving against a temporary class loader, exit early in order
// to avoid storing the resolved Class in the bean definition.
if (classLoaderToUse != beanClassLoader) {
return ClassUtils.forName(className, classLoaderToUse);
}
}
// Step4:利用Class.forName返回一个Class类型。
return mbd.resolveBeanClass(beanClassLoader);
}
总结
到此我们就获取到了beanName
对应的class类型,从而判断其是否是一个FactoryBean
。有些朋友看到这里应该会比较迷惑BeanFactory
和FactoryBean
,这里简单给大家解释一下。
BeanFactory
:是一个Bean工厂,是一个IoC容易,用于存放Bean实例的。FactoryBean
:它本身是一种特殊的bean,通过FactoryBean
可以创建出指定的bean实例,即调用其getObject()
获得。所以也就是BeanFactory
是用来管理FactoryBean
的。
注意
在xml文件中我们指定的是
FactoryBean
,而非目标Bean通过
context.getBean("car")
方式获取到的bean实例是目标bean,如果我们想要的是FactoryBean本身
,而非目标bean实例,则通过context.getBean("&car")
就可以获得。FactoryBean
的getObject()
方法是在第一次getBean的时候才会被调用,如果isSingleton()
方法返回true,则下次使用时直接从BeanFactory
里面获取。
讲清楚了这个概念之后,下篇文章我们来接着看bean实例的创建过程,敬请期待。
欢迎关注我,共同学习