深入了解spring中的FactoryBean(一)

一般情况下,spring通过反射机制利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean过程比较复杂,如果按照传统方式,灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。spring为此提供了一个org.springframework.beans.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑

下面展示 FactoryBean,注意看代码中的注释,注意看代码中的注释,注意看代码中的注释

package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
    //返回由FactoryBean创建的bean实例,如果isSingleton返回true,则该实例会放到Spring容器中单实例缓存池中。
    @Nullable
    T getObject() throws Exception;
    //返回FactoryBean创建的bean类型
    @Nullable
    Class<?> getObjectType();
    //返回由FactoryBean创建的bean实例的作用域是singleton还是prototype
    default boolean isSingleton() {
        return true;
    }
}

当我们的类实现了FactoryBean时,通过applicationContext.getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

例如:
下面展示 具体实现

// 定义一个MyFactoryBean类实现FactoryBean接口,重写其方法

import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component
public class MyFactoryBean implements FactoryBean {
    //返回自定义的功能类PersionServiceImpl
    @Override
    public Object getObject() throws Exception {
        return new PersionServiceImpl();
    }
    //返回自定义的接口PersionService
    @Override
    public Class<?> getObjectType() {
        return PersionService.class;
    }

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

public interface PersionService {
    void printName();
}
public class PersionServiceImpl implements PersionService{
    @Override
    public void printName() {
        System.out.println("===中路杀神====");
    }
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class FactoryBeanTest {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void ftest(){
        PersionService persionService = applicationContext.getBean(PersionService.class);
        persionService.printName();
    }
}

运行结果如下

===中路杀神====

下面源码分析一波

AbstractApplicationContext#getBean()

    public <T> T getBean(Class<T> requiredType) throws BeansException {
        this.assertBeanFactoryActive();
        return this.getBeanFactory().getBean(requiredType);
    }

    public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
        this.assertBeanFactoryActive();
        //getBeanFactory()返回的是DefaultListableBeanFactory
        return this.getBeanFactory().getBean(requiredType, args);
    }

DefaultListableBeanFactory#getBean()

    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return this.getBean(requiredType, (Object[])null);
    }

    public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
        Assert.notNull(requiredType, "Required type must not be null");
        //这里我们重点看resolveBean()方法
        Object resolved = this.resolveBean(ResolvableType.forRawClass(requiredType), args, false);
        if (resolved == null) {
            throw new NoSuchBeanDefinitionException(requiredType);
        } else {
            return resolved;
        }
    }

this.resolveBean()

    @Nullable
    private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
        //NamedBeanHolder对应我们的例子 beanName是MyFactoryBean,beanInstance是PersionService
        //下面看看resolveNamedBean是怎么做到的映射
        NamedBeanHolder<T> namedBean = this.resolveNamedBean(requiredType, args, nonUniqueAsNull);
        if (namedBean != null) {
            return namedBean.getBeanInstance();
        } else {
            BeanFactory parent = this.getParentBeanFactory();
            if (parent instanceof DefaultListableBeanFactory) {
                return ((DefaultListableBeanFactory)parent).resolveBean(requiredType, args, nonUniqueAsNull);
            } else if (parent != null) {
                ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
                if (args != null) {
                    return parentProvider.getObject(args);
                } else {
                    return nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable();
                }
            } else {
                return null;
            }
        }
    }

resolveNamedBean()

    @Nullable
    private <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
        Assert.notNull(requiredType, "Required type must not be null");
        //这个方法是根据传入的Class类型来获取BeanName,因为我们有一个接口有多个实现类的情况(多态),
        //所以这里返回的是一个String数组。
        //这里需要注意的是,我们调用getBean方法传入的type为PersionService.class类型,但是我们在Spring容器中没有注入PersionService类型的bean
        //正常来说我们在这里是获取不到beanName呢。但是事实我们获取到了,看下面我们对getBeanNamesForType的分析
        String[] candidateNames = this.getBeanNamesForType(requiredType);
        String[] var6;
        int var7;
        int var8;
        String beanName;
        if (candidateNames.length > 1) {
            List<String> autowireCandidates = new ArrayList(candidateNames.length);
            var6 = candidateNames;
            var7 = candidateNames.length;

            for(var8 = 0; var8 < var7; ++var8) {
                beanName = var6[var8];
                if (!this.containsBeanDefinition(beanName) || this.getBeanDefinition(beanName).isAutowireCandidate()) {
                    autowireCandidates.add(beanName);
                }
            }

            if (!autowireCandidates.isEmpty()) {
                candidateNames = StringUtils.toStringArray(autowireCandidates);
            }
        }

        if (candidateNames.length == 1) {
            String beanName = candidateNames[0];
            //这块逻辑是封装NamedBeanHolder的,对应我们的代码beanName为MyFactoryBean,beanInstance为PersionService,跟进去看看代码流程,我们会在下篇内容说。
            return new NamedBeanHolder(beanName, this.getBean(beanName, requiredType.toClass(), args));
        } else {
            if (candidateNames.length > 1) {
                Map<String, Object> candidates = new LinkedHashMap(candidateNames.length);
                var6 = candidateNames;
                var7 = candidateNames.length;

                for(var8 = 0; var8 < var7; ++var8) {
                    beanName = var6[var8];
                    if (this.containsSingleton(beanName) && args == null) {
                        Object beanInstance = this.getBean(beanName);
                        candidates.put(beanName, beanInstance instanceof NullBean ? null : beanInstance);
                    } else {
                        candidates.put(beanName, this.getType(beanName));
                    }
                }

                String candidateName = this.determinePrimaryCandidate(candidates, requiredType.toClass());
                if (candidateName == null) {
                    candidateName = this.determineHighestPriorityCandidate(candidates, requiredType.toClass());
                }

                if (candidateName != null) {
                    Object beanInstance = candidates.get(candidateName);
                    if (beanInstance == null || beanInstance instanceof Class) {
                        beanInstance = this.getBean(candidateName, requiredType.toClass(), args);
                    }

                    return new NamedBeanHolder(candidateName, beanInstance);
                }

                if (!nonUniqueAsNull) {
                    throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
                }
            }

            return null;
        }
    }

getBeanNamesForType()

 public String[] getBeanNamesForType(ResolvableType type) {
        return this.getBeanNamesForType(type, true, true);
    }

    public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
        Class<?> resolved = type.resolve();
        return resolved != null && !type.hasGenerics() ? this.getBeanNamesForType(resolved, includeNonSingletons, allowEagerInit) : this.doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
    }

    public String[] getBeanNamesForType(@Nullable Class<?> type) {
        return this.getBeanNamesForType(type, true, true);
    }

    public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
        if (this.isConfigurationFrozen() && type != null && allowEagerInit) {
            Map<Class<?>, String[]> cache = includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType;
            String[] resolvedBeanNames = (String[])cache.get(type);
            if (resolvedBeanNames != null) {
                return resolvedBeanNames;
            } else {
            //我们看这里的调用
                resolvedBeanNames = this.doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
                if (ClassUtils.isCacheSafe(type, this.getBeanClassLoader())) {
                    cache.put(type, resolvedBeanNames);
                }

                return resolvedBeanNames;
            }
        } else {
            return this.doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
        }
    }

继续看上面代码块的doGetBeanNamesForType()

    private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
        List<String> result = new ArrayList();
        //循环所有的beanName 这个是在Spring容器启动解析Bean的时候放入到这个List中的
        Iterator var5 = this.beanDefinitionNames.iterator();

        while(true) {
            String beanName;
            do {
                if (!var5.hasNext()) {
                    var5 = this.manualSingletonNames.iterator();

                    while(var5.hasNext()) {
                        beanName = (String)var5.next();

                        try {
                            if (this.isFactoryBean(beanName)) {
                                if ((includeNonSingletons || this.isSingleton(beanName)) && this.isTypeMatch(beanName, type)) {
                                    result.add(beanName);
                                    continue;
                                }

                                beanName = "&" + beanName;
                            }
//我们需要重点关注的是isTypeMatch这个方法 ,如果isTypeMatch这个方法返回true的话,我们会把这个beanName即 MyFactoryBean 放入到result中返回
//我们接着看isTypeMatch方法
 
                            if (this.isTypeMatch(beanName, type)) {
                                result.add(beanName);
                            }
                        } catch (NoSuchBeanDefinitionException var13) {
                            this.logger.trace(LogMessage.format("Failed to check manually registered singleton with name '%s'", beanName), var13);
                        }
                    }

                    return StringUtils.toStringArray(result);
                }

                beanName = (String)var5.next();
            } while(this.isAlias(beanName));

            try {
                RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                if (!mbd.isAbstract() && (allowEagerInit || (mbd.hasBeanClass() || !mbd.isLazyInit() || this.isAllowEagerClassLoading()) && !this.requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                    boolean isFactoryBean = this.isFactoryBean(beanName, mbd);
                    BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
                    boolean matchFound = false;
                    boolean allowFactoryBeanInit = allowEagerInit || this.containsSingleton(beanName);
                    boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit();
                    if (!isFactoryBean) {
                        if (includeNonSingletons || this.isSingleton(beanName, mbd, dbd)) {
                            matchFound = this.isTypeMatch(beanName, type, allowFactoryBeanInit);
                        }
                    } else {
                        if (includeNonSingletons || isNonLazyDecorated || allowFactoryBeanInit && this.isSingleton(beanName, mbd, dbd)) {
                            matchFound = this.isTypeMatch(beanName, type, allowFactoryBeanInit);
                        }

                        if (!matchFound) {
                            beanName = "&" + beanName;
                            matchFound = this.isTypeMatch(beanName, type, allowFactoryBeanInit);
                        }
                    }

                    if (matchFound) {
                        result.add(beanName);
                    }
                }
            } catch (BeanDefinitionStoreException | CannotLoadBeanClassException var14) {
                if (allowEagerInit) {
                    throw var14;
                }

                LogMessage message = var14 instanceof CannotLoadBeanClassException ? LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) : LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName);
                this.logger.trace(message, var14);
                this.onSuppressedException(var14);
            } catch (NoSuchBeanDefinitionException var15) {
            }
        }
    }

isTypeMatch()

    protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {
        String beanName = this.transformedBeanName(name);
        boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
        //因为我们这里是用的AbstractApplicationContext的子类来从Spring容器中获取Bean
        //获取beanName为MyFactoryBean的Bean实例 这里是可以获取到Bean实例的
        Object beanInstance = this.getSingleton(beanName, false);
        if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
         //MyFactoryBean是FactoryBean的一个实现类
            if (beanInstance instanceof FactoryBean) {
                if (isFactoryDereference) {
                    return typeToMatch.isInstance(beanInstance);
                } else {
           //这里就是从MyFactoryBean中获取type类型,调用了MyFactoryBean的getObjectType方法,返回的是PersionService.class类型
                    Class<?> type = this.getTypeForFactoryBean((FactoryBean)beanInstance);
                    //typeToMatch是我们传入的PersionService.class与MyFactoryBean的getObjectType返回的PersionService.class去比较,那必然返回true;
                    return type != null && typeToMatch.isAssignableFrom(type);
                }
            } else {
                if (!isFactoryDereference) {
                    if (typeToMatch.isInstance(beanInstance)) {
                        return true;
                    }

                    if (typeToMatch.hasGenerics() && this.containsBeanDefinition(beanName)) {
                        RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                        Class<?> targetType = mbd.getTargetType();
                        if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) {
                            Class<?> classToMatch = typeToMatch.resolve();
                            if (classToMatch != null && !classToMatch.isInstance(beanInstance)) {
                                return false;
                            }

                            if (typeToMatch.isAssignableFrom(targetType)) {
                                return true;
                            }
                        }

                        ResolvableType resolvableType = mbd.targetType;
                        if (resolvableType == null) {
                            resolvableType = mbd.factoryMethodReturnType;
                        }

                        return resolvableType != null && typeToMatch.isAssignableFrom(resolvableType);
                    }
                }

                return false;
            }
        } else if (this.containsSingleton(beanName) && !this.containsBeanDefinition(beanName)) {
            return false;
        } else {
            BeanFactory parentBeanFactory = this.getParentBeanFactory();
            if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
                return parentBeanFactory.isTypeMatch(this.originalBeanName(name), typeToMatch);
            } else {
                RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
                Class<?> classToMatch = typeToMatch.resolve();
                if (classToMatch == null) {
                    classToMatch = FactoryBean.class;
                }

                Class<?>[] typesToMatch = FactoryBean.class == classToMatch ? new Class[]{classToMatch} : new Class[]{FactoryBean.class, classToMatch};
                Class<?> predictedType = null;
                if (!isFactoryDereference && dbd != null && this.isFactoryBean(beanName, mbd) && (!mbd.isLazyInit() || allowFactoryBeanInit)) {
                    RootBeanDefinition tbd = this.getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
                    Class<?> targetType = this.predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
                    if (targetType != null && !FactoryBean.class.isAssignableFrom(targetType)) {
                        predictedType = targetType;
                    }
                }

                if (predictedType == null) {
                    predictedType = this.predictBeanType(beanName, mbd, typesToMatch);
                    if (predictedType == null) {
                        return false;
                    }
                }

                ResolvableType beanType = null;
                if (FactoryBean.class.isAssignableFrom(predictedType)) {
                    if (beanInstance == null && !isFactoryDereference) {
                        beanType = this.getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit);
                        predictedType = beanType.resolve();
                        if (predictedType == null) {
                            return false;
                        }
                    }
                } else if (isFactoryDereference) {
                    predictedType = this.predictBeanType(beanName, mbd, FactoryBean.class);
                    if (predictedType == null || !FactoryBean.class.isAssignableFrom(predictedType)) {
                        return false;
                    }
                }

                if (beanType == null) {
                    ResolvableType definedType = mbd.targetType;
                    if (definedType == null) {
                        definedType = mbd.factoryMethodReturnType;
                    }

                    if (definedType != null && definedType.resolve() == predictedType) {
                        beanType = definedType;
                    }
                }

                return beanType != null ? typeToMatch.isAssignableFrom(beanType) : typeToMatch.isAssignableFrom(predictedType);
            }
        }
    }

总结

  1. 我们在调用MyFactoryBean的getObjectType方法的时候,获取到的值为:PersionService和我们传入的type是一样的类型。所以这里返回true,根据我们上面说的如果isTypeMatch返回true的话,我们返回的beanName为MyFactoryBean
  2. 我们调用getBean(Class requiredType)方法根据类型来获取容器中的bean的时候,对应我们的例子就是:根据类型PersionService来从Spring容器中获取Bean(首先明确的一点是在Spring容器中没有PersionService类型的BeanDefinition)
  3. Spring在根据type去获取Bean的时候,会先获取到beanName(即MyFactoryBean)。获取beanName的过程是:先循环Spring容器中的所有的beanName,然后根据beanName获取对应的BeanDefinition,如果当前bean是FactoryBean的类型,则会从Spring容器中根据beanName获取对应的Bean实例,接着调用获取到的Bean实例的getObjectType方法获取到Class类型,判断此Class类型和我们传入的Class是否是同一类型。如果是则返回测beanName,对应到我们这里就是:根据MyFactoryBean获取到MyFactoryBean实例,调用MyFactoryBean的getObjectType方法获取到返回值PersionService.class。和我们传入的类型一致,所以这里获取的beanName为MyFactoryBean。
  4. 我们分析中有NamedBeanHolder这个类,其中beanName是MyFactoryBean,beanInstance为PersionService,这一点很重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_当i已成往事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值