Spring IOC(七)类型推断
Spring IOC(七)类型推断
Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)
Spring 容器中可以根据 beanName 查找其类型,其推断方式和 bean 的创建方式密切相关,并且 Spring 中有一个原则是尽可能的不要通过创建 bean 来获取其类型,除了 FactoryBean 只有通过创建对象调用其 getObjectType 方法,但也只是部分的创建该 FactoryBean(所谓的部分创建是指只实例化对象,而不进行属性注入和初始化过程):
- 对于缓存中存在单例的 bean,则直接根据对象获取其类型。
- 对于 FactoryBean 创建的 bean,Spring 会部分实例化,调用 FactoryBean#getObjectType() 方法。
- 对于工厂方法,Spring 不会实例化这个对象,而是用该方法的返回值类型来进行推断。如果该方法定义了泛型且返回值的类型恰好和泛型有关,则要通过传递的参数来进一步推断,但在 @Spring 5.1.3 似乎有 BUG。
- 工厂方法也有可能返回一个 FactoryBean 类型,静态工厂和实例工厂方法处理方法有些不一样。都有两种方式推断类型:一是根据方法的返回值类型进行推断;二是实例化这个 FactoryBean 后调用 getObjectType 方法。对于实例工厂,如果这个工厂还没有实例话就只执行第一种推断方式。
一、Spring 类型推断测试
(1) 环境准备
public class User {
}
// 如果 FactoryBean 没有指定 User 类型则要部分实例化对象
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
public class UserFactory {
// 1. 实例工厂
public User getObject1() {
return new User();
}
// 2. 静态工厂
public static User getObject2() {
return new User();
}
// 3.1 带参的工厂方法
public User getObject3(String username, String password) {
return new User();
}
// 3.2 带泛型的工厂方法,但返回值类型和泛型无关
public <T, K, V> User getObject4(T t, String username) {
return new User();
}
// 3.3 带泛型的工厂方法,但返回值类型由参数决定
public <T, K, V> T getObject5(T t) {
return t;
}
// 4.1 静态工厂方法返回类型为 FactoryBean
public static FactoryBean<User> getObject6() {
return new UserFactoryBean();
}
// 4.2 实例工厂方法返回类型为 FactoryBean
public FactoryBean<User> getObject7() {
return new UserFactoryBean();
}
}
(2) xcml 配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--1. 直接定义 className-->
<bean id="bean1" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.User"/>
<!--2. FactoryBean-->
<bean id="bean2" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactoryBean"/>
<!--3. 实例工厂-->
<bean id="userFactory" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory"/>
<bean id="bean3" factory-bean="userFactory" factory-method="getObject1"/>
<!--4. 静态工厂-->
<bean id="bean4" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory" factory-method="getObject2"/>
<!--5. 带参的工厂方法,和构造器注入类似-->
<!--5.1 工厂方法没有定义泛型-->
<bean id="bean5.1" factory-bean="userFactory" factory-method="getObject3">
<constructor-arg index="0" value="0"/>
<constructor-arg index="1" value="1"/>
</bean>
<!--5.2 工厂方法定义泛型,但返回值类型与泛型无关-->
<bean id="bean5.2" factory-bean="userFactory" factory-method="getObject4">
<constructor-arg index="0" value="0"/>
<constructor-arg index="1" value="1"/>
</bean>
<!--5.3 工厂方法定义泛型,返回值类型与参数类型决定-->
<bean id="bean5.3" factory-bean="userFactory" factory-method="getObject5">
<constructor-arg index="0" value="0"/>
</bean>
<!--6 静态工厂方法的返回值为一个 FactoryBean 类型-->
<bean id="bean6.1" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory" factory-method="getObject6"/>
<!--7 实例工厂方法的返回值为一个 FactoryBean 类型-->
<bean id="bean6.2" factory-bean="userFactory" factory-method="getObject7"/>
</beans>
(3) 测试一把
@Test
public void test() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(lbf);
reader.loadBeanDefinitions(new ClassPathResource("spring-context-factory.xml"));
// 1. 直接定义 className
Assert.assertTrue(lbf.isTypeMatch("bean1", User.class));
// 2. FactoryBean
Assert.assertTrue(lbf.isTypeMatch("bean2", User.class));
// 3. 实例工厂
Assert.assertTrue(lbf.isTypeMatch("bean3", User.class));
// 4. 静态工厂
Assert.assertTrue(lbf.isTypeMatch("bean4", User.class));
// 5.1 工厂方法没有定义泛型
Assert.assertTrue(lbf.isTypeMatch("bean5.1", User.class));
// 5.2 工厂方法定义泛型,但返回值类型与泛型无关
Assert.assertTrue(lbf.isTypeMatch("bean5.2", User.class));
// 5.3 工厂方法定义泛型,返回值类型与参数类型决定,无法获取 @Spring 5.1.3
Assert.assertFalse(lbf.isTypeMatch("bean5.3", User.class));
// 6.1 静态工厂方法返回类型为 FactoryBean
Assert.assertTrue(lbf.isTypeMatch("bean6.1", User.class));
// 6.2 实例工厂方法返回类型为 FactoryBean,如果实例化这个工厂后可以获取其类型
Assert.assertFalse(lbf.isTypeMatch("bean6.2", User.class));
lbf.getBean("userFactory");
Assert.assertTrue(lbf.isTypeMatch("bean6.2", User.class));
}
可以看到工厂方法带有泛型且返回值类型和泛型有关后 Spring 不能正确处理了,另外实例工厂的工厂方法返回 FactoryBean
二、Spring 类型推断源码分析
2.1 类型匹配的入口 - isTypeMatch
@Override
public boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException {
return isTypeMatch(name, ResolvableType.forRawClass(typeToMatch));
}
@Override
public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
// 1. 根据实例化后的对象获取 bean 的类型,注意 FactoryBean 的处理即可
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
// 1.1 如果是 FactoryBean 类型,此时需要判断是否要查找的就是这个工厂对象,判断 beanName 是否是以 & 开头
// 如果是其创建的类型,则需要调用 getTypeForFactoryBean 从这个 FactoryBean 实例中获取真实类型
if (beanInstance instanceof FactoryBean) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
return (type != null && typeToMatch.isAssignableFrom(type));
} else {
return typeToMatch.isInstance(beanInstance);
}
// 1.2 如果是普通 bean 则可直接判断类型,当然 Spring 还考虑的泛型的情况
} else if (!BeanFactoryUtils.isFactoryDereference(name)) {
if (typeToMatch.isInstance(beanInstance)) {
return true;
} else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
// AOP 有关 ????
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
Class<?> targetType = mbd.getTargetType();
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) &&
typeToMatch.isAssignableFrom(targetType)) {
Class<?> classToMatch = typeToMatch.resolve();
return (classToMatch == null || classToMatch.isInstance(beanInstance));
}
}
}
return false;
} else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
// null instance registered
return false;
}
// 2. 父工厂,没什么好说的
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
}
// 3. 下面就要从 bean 的定义中获取该 bean 的类型了
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
Class<?> classToMatch = typeToMatch.resolve();
if (classToMatch == null) {
classToMatch = FactoryBean.class;
}
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
// 3.1 AOP 代理时会将原始的 BeanDefinition 存放到 decoratedDefinition 属性中,可以行忽略这部分
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
return typeToMatch.isAssignableFrom(targetClass);
}
}
// 3.2 predictBeanType 推断 beanName 的类型,主要的逻辑
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
if (beanType == null) {
return false;
}
// 3.3 处理 FactoryBean 类型
if (FactoryBean.class.isAssignableFrom(beanType)) {
if (!BeanFactoryUtils.isFactoryDereference(name) && beanInstance == null) {
// 此时需要从 FactoryBean 中推断出真实类型
beanType = getTypeForFactoryBean(beanName, mbd);
if (beanType == null) {
return false;
}
}
// 3.4 beanType 不是 FactoryBean 类型,但是又要获取 FactoryBean 的类型???
} else if (BeanFactoryUtils.isFactoryDereference(name)) {
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
// type but we nevertheless are being asked to dereference a FactoryBean...
// Let's check the original bean class and proceed with it if it is a FactoryBean.
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
return false;
}
}
// 3.5 优先从缓存中判断,可以比较泛型
ResolvableType resolvableType = mbd.targetType;
if (resolvableType == null) {
resolvableType = mbd.factoryMethodReturnType;
}
if (resolvableType != null && resolvableType.resolve() == beanType) {
return typeToMatch.isAssignableFrom(resolvableType);
}
return typeToMatch.isAssignableFrom(beanType);
}
上面的代码一大堆,逻辑也比较复杂,我们现在只需要明白三点:
- Spring 先直接从缓存中获取这个 bean 实例,再根据对象推断其类型。如果 bean 还没有创建或者干脆就不是单例,则只能根据定义这个 bean 的 BeanDefinition 获取了。
- 先根据 BeanDefinition 获取其当前 bean 的类型,Spring 全部委托给了 predictBeanType(beanName, mbd, typesToMatch) 方法。
- 如果当前 bean 是 FactoryBean,则还需要进一步获取其真实类型。这个过程由 getTypeForFactoryBean 方法完成,这个方法有两个重载的方法,即可以直接通过实例对象获取,也可以通过定义的 BeanDefinition 获取对象类型。
下面我们就分别介绍一下这两个方法。
2.2 从 BeanDefinition 推断类型 - predictBeanType
我们先从简单的看起,AbstractBeanFactory#predictBeanType 实现了这个方法,其子类又重载了这个方法 AbstractAutowireCapableBeanFactory#predictBeanType。
(1) AbstractBeanFactory#predictBeanType
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
// 1. 直接从缓存中获取
Class<?> targetType = mbd.getTargetType();
if (targetType != null) {
return targetType;
}
// 2. 工厂方法一律返回 null,子类会重载后解析对应的 getFactoryMethodName
if (mbd.getFactoryMethodName() != null) {
return null;
}
// 3. 解析 BeanDefinition 的 className,如果已经加载则直接从缓存中获取
return resolveBeanClass(mbd, beanName, typesToMatch);
}
可以看到最终是从 BeanDefinition 中解析配置的 className 属性,将其加载到 JVM 中。它有三个参数,毫无疑问的是 mbd 是必须的,beanName 记录异常时使用,那 typesToMatch 是干嘛的呢?带着这个疑问我们看一下源码。
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName,
final Class<?>... typesToMatch) throws CannotLoadBeanClassException {
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
return doResolveBeanClass(mbd, typesToMatch);
}
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader classLoaderToUse = beanClassLoader;
// 1. Spring 自定义的类型器 DecoratingClassLoader 修改了 JDK 的类加载规则,自己先加载一把,没有再特派给父加载器
// 这就产生了一个问题,每个临时的类加载器可能加载同一个类可能出现多个
// 所以可以将其加入到 excludeClass 仍采用双亲委派
if (!ObjectUtils.isEmpty(typesToMatch)) {
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
classLoaderToUse = tempClassLoader;
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
// 2. 如果 className 含有点位符,解析后发生了变化,则不用缓存,以后每次都解析一次
String className = mbd.getBeanClassName();
if (className != null) {
Object evaluated = evaluateBeanDefinitionString(className, mbd);
if (!className.equals(evaluated)) {
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);
}
}
if (classLoaderToUse != beanClassLoader) {
return ClassUtils.forName(className, classLoaderToUse);
}
}
// 3. 解析 className 后缓存起来
return mbd.resolveBeanClass(beanClassLoader);
}
至此,根据 BeanDefinition 解析 bean 的类型就完成了,最终还是回到了我们在 xml 文件中配置的 class 上来了,只是 Spring 的解析考虑了很多情况,一下子就复杂起来了。 想必现在对 typesToMatch 也有一定的了解了,就是为了保证要匹配的类型是同一个类加载器加载的,这里也就是 JDK 的系统类加载器 - AppClassLoader,这样调用 typeToMatch.isAssignableFrom(type) 方法才有意义。
(2) AbstractAutowireCapableBeanFactory#predictBeanType
AbstractAutowireCapableBeanFactory 又对 predictBeanType 进行了重载,增加了对工厂方法 factoryMethodName 的解析。
@Override
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
// 1. 增加了对工厂 factoryMethod 的解析
Class<?> targetType = determineTargetType(beanName, mbd, typesToMatch);
// 2. 后置处理器 SmartInstantiationAwareBeanPostProcessors
if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
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;
}
}
}
}
return targetType;
}
// 怎么样,逻辑还是之前的一样,只是增加对 factoryMethodName 的处理
protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
Class<?> targetType = mbd.getTargetType();
if (targetType == null) {
targetType = (mbd.getFactoryMethodName() != null ?
getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
resolveBeanClass(mbd, beanName, typesToMatch));
if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
mbd.resolvedTargetType = targetType;
}
}
return targetType;
}
在这里,我们重点关注 getTypeForFactoryMethod 方法,Spring 是如何从一个工厂方法中获取其类型的。
protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
// 1. 缓存中直接取
ResolvableType cachedReturnType = mbd.factoryMethodReturnType;
if (cachedReturnType != null) {
return cachedReturnType.resolve();
}
Class<?> factoryClass;
boolean isStatic = true;
// 2. 在 Spring 中有静态工厂和实例工厂之分,如果是实例工厂名称不能是当前的 beanName
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 2.1 获取实例工厂的类型
factoryClass = getType(factoryBeanName);
isStatic = false;
} else {
// 2.2 静态工厂只能是静态方法,解析自己的 BeanDefinition 就可以了
factoryClass = resolveBeanClass(mbd, beanName, typesToMatch);
}
if (factoryClass == null) {
return null;
}
// 2.3 如果是 CGLIB 代理,获取其真实类型
factoryClass = ClassUtils.getUserClass(factoryClass);
// 3.1 如果有多个方法同名,则取其返回傎的公有类型,除非为 null
Class<?> commonType = null;
// 3.2 缓存这个工厂方法
Method uniqueCandidate = null;
// 3.3 如果方法含有泛型,则需要根据传递的参数进一步判断返回值类型
int minNrOfArgs =
(mbd.hasConstructorArgumentValues() ? mbd.getConstructorArgumentValues().getArgumentCount() : 0);
Method[] candidates = this.factoryMethodCandidateCache.computeIfAbsent(
factoryClass, ReflectionUtils::getUniqueDeclaredMethods);
// 4. 遍历所有的名称为工厂方法的
for (Method candidate : candidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate) &&
candidate.getParameterCount() >= minNrOfArgs) {
// 4.1 方法中定义了泛型,则需要将配置的构造参数进行比较了,但似乎有问题
// 4.1.1 getTypeParameters 获取定义的泛型个数
if (candidate.getTypeParameters().length > 0) {
// 4.1.2 getParameterTypes 获取该方法的参数列表
Class<?>[] paramTypes = candidate.getParameterTypes();
String[] paramNames = null;
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
Object[] args = new Object[paramTypes.length];
// 4.1.3 根据类型和参数名匹配真实的参数
for (int i = 0; i < args.length; i++) {
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
if (valueHolder == null) {
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
}
if (valueHolder != null) {
args[i] = valueHolder.getValue();
usedValueHolders.add(valueHolder);
}
}
// 4.1.4 解析返回值对应的泛型类型
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
candidate, args, getBeanClassLoader());
uniqueCandidate = (commonType == null && returnType == candidate.getReturnType() ?
candidate : null);
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
if (commonType == null) {
return null;
}
// 4.2 直接获取方法的返回值类型,如果有多个同名方法取其公共的祖先即可,没有就直接返回 null
} else {
// 第一次匹配上会缓存这个方法,但再次匹配上了,不好意思有重名的方法,直接清空
uniqueCandidate = (commonType == null ? candidate : null);
commonType = ClassUtils.determineCommonAncestor(candidate.getReturnType(), commonType);
if (commonType == null) {
return null;
}
}
}
}
// 5.1 如果同名的方法只有一个,那么将这个工厂方法直接缓存起来
mbd.factoryMethodToIntrospect = uniqueCandidate;
if (commonType == null) {
return null;
}
// 5.2 如果只有唯一的工厂方法,那么尽可能缓存完型的类型,包括泛型。所以再解析一次用于缓存
cachedReturnType = (uniqueCandidate != null ?
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
mbd.factoryMethodReturnType = cachedReturnType;
return cachedReturnType.resolve();
}
根据工厂方法推断 bean 的类型看起来很复杂,但逻辑还是很清晰的:
- 直接从缓存中获取这个工厂方法的返回值类型。
- 解析工厂方法的类型,这里分为静态工厂和实例工厂,静态工厂即为自己本身,实例工厂为配置的 factory-bean
- 遍历这个工厂类的每个和 factory-method 同名的工厂方法,包括其父类。Spring 增加了对泛型返回值方法的支持,但我在测试的时候失败了,不知道是不是使用不对。总之,就是遍历这些方法的返回值类型,如果有多个就取其公共的类型。
- 如果只有唯一的一个工厂方法,缓存起来,同时缓存解析后的类型,尽可能保存完整的类型,包括泛型。
对于泛型返回值类型再多说一句,Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod( candidate, args, getBeanClassLoader());
在测试时确实没有问题,后来发现是 Spring 在解析 xml 文件时对构造参数做了一个封装,也就是 valueHolder.getValue()
不是配置的类型,而是 TypedStringValue 类型,导致解析出现问题。
2.3 根据 FactoryBean 获取真实类型 - getTypeForFactoryBean
getTypeForFactoryBean 相对来说比较简单,我们先说这个方法。AbstractBeanFactory#getTypeForFactoryBean 实现了这个方法,其子类又重载了这个方法 AbstractAutowireCapableBeanFactory#getTypeForFactoryBean
(1) AbstractBeanFactory#getTypeForFactoryBean
protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
if (!mbd.isSingleton()) {
return null;
}
FactoryBean<?> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
return getTypeForFactoryBean(factoryBean);
}
protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
return factoryBean.getObjectType();
}
怎么样是不是很简单,先创建这个 FactoryBean 的实例,然后调用其 getObjectType 方法获取真实类型。但问题又来了,我们仅仅需要获取这个 bean 的类型,却要实例化与之相关的一系列对象,是不是代价太昂贵了,怎么规避这个问题呢?在其子类 AbstractAutowireCapableBeanFactory 中对这个方法做了进一步的增强,一起看一下。
(2) AbstractAutowireCapableBeanFactory#getTypeForFactoryBean
@Override
protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
// 1. 处理 mbd.getInstanceSupplier(),另外一种创建 bean 的方式,@Sping 5.0 提供,我们先忽略...
// if (mbd.getInstanceSupplier() != null) ...
// 2. 这个 FactoryBean 也可能是其他的工厂的工厂方法创建的
String factoryBeanName = mbd.getFactoryBeanName();
String factoryMethodName = mbd.getFactoryMethodName();
// 3. 实例工厂创建 FactoryBean<User>
if (factoryBeanName != null) {
// 3.1 如果实例工厂的 className 已经解析过了,就直接从其工厂方法的返回值类型进行推断
if (factoryMethodName != null) {
BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
if (fbDef instanceof AbstractBeanDefinition) {
AbstractBeanDefinition afbDef = (AbstractBeanDefinition) fbDef;
if (afbDef.hasBeanClass()) {
Class<?> result = getTypeForFactoryBeanFromMethod(afbDef.getBeanClass(), factoryMethodName);
if (result != null) {
return result;
}
}
}
}
// 3.2 判断这个实例工厂有没有实例化,如果没有则直接 Game Over
// 因为下面我们要调用 FactoryBean#getObjectType(),不能就是要部分实例化这个 FactoryBean 对象
// 如果连创建这个 FactoryBean 的工厂都未实例化,那么更谈不上创建 FactoryBean 了
// Spring 不会为了获取一个 bean 的类型去循环创建 bean
if (!isBeanEligibleForMetadataCaching(factoryBeanName)) {
return null;
}
}
// 4. 现在我们要先部分实例化这个 FactoryBean,调用其 getObjectType() 来获取对象类型
FactoryBean<?> fb = (mbd.isSingleton() ?
getSingletonFactoryBeanForTypeCheck(beanName, mbd) :
getNonSingletonFactoryBeanForTypeCheck(beanName, mbd));
if (fb != null) {
// 4.1 调用 FactoryBean#getObjectType() 获取类型
Class<?> result = getTypeForFactoryBean(fb);
if (result != null) {
return result;
// 4.2 如果部分实例化还是获取不到,没办法了只有将这个 FactoryBean 全部实例化出来了
} else {
return super.getTypeForFactoryBean(beanName, mbd);
}
}
// 5. 静态工厂创建 FactoryBean,这种情况下 fb=null,我们可以解析该方法的返回值类型
if (factoryBeanName == null && mbd.hasBeanClass()) {
// 5.1 解析方法的返回值的泛型类型,FactoryBean<User>
if (factoryMethodName != null) {
return getTypeForFactoryBeanFromMethod(mbd.getBeanClass(), factoryMethodName);
// 5.2 该类就是一个 FactoryBean,则直接解析其泛型就好 FactoryBean<User>
} else {
return GenericTypeResolver.resolveTypeArgument(mbd.getBeanClass(), FactoryBean.class);
}
}
return null;
}
这个方法思路很清晰,就是在尽可能不去实例化对象的情况下,拿到这个 FactoryBean 的真实创建的类型。重点关注下面三个方法:
getTypeForFactoryBeanFromMethod
工厂方法创建 FactoryBean<...>,直接解析其中的泛型getSingletonFactoryBeanForTypeCheck
和getNonSingletonFactoryBeanForTypeCheck
都先尝试部分实例化这个 FactoryBean,如果任然无法获取,则需要完整的实例化这个对象。
private Class<?> getTypeForFactoryBeanFromMethod(Class<?> beanClass, final String factoryMethodName) {
class Holder {
Class<?> value = null;
}
final Holder objectType = new Holder();
Class<?> fbClass = ClassUtils.getUserClass(beanClass);
// 解析工厂方法的返回值 FactoryBean<User> 类型,如果有多个同名的方法则取公共的类型
ReflectionUtils.doWithMethods(fbClass, method -> {
if (method.getName().equals(factoryMethodName) &&
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
// 解析 FactoryBean<User> 中的泛型类型
Class<?> currentType = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
if (currentType != null) {
objectType.value = ClassUtils.determineCommonAncestor(currentType, objectType.value);
}
}
});
return (objectType.value != null && Object.class != objectType.value ? objectType.value : null);
}
getTypeForFactoryBeanFromMethod 实际上是在解析方法返回值 FactoryBean
public class UserFactory {
public static FactoryBean<User> getObject6() {
return new UserFactoryBean();
}
}
至于 getSingletonFactoryBeanForTypeCheck 和 getNonSingletonFactoryBeanForTypeCheck 两个方法也只是实例化了这个 bean。调用了 createBeanInstance
方法。
private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
BeanWrapper bw = createBeanInstance(beanName, mbd, null);
instance = bw.getWrappedInstance();
return fb;
}
}
参考:
1 . 《》:<>
每天用心记录一点点。内容也许不重要,但习惯很重要!