Spring Framework 组件注册 之 FactoryBean (2)

要想了解FactoryBean的执行过程,就需要结合Spring容器启动的过程来进行分析。而spring容器的启动过程经过了纷繁复杂的步骤。为了尽可能少的入坑和挖坑,下面仅结合FactoryBean相关的源码进行说明。

在开始入坑之旅之前,结合前面的例子做几点说明,方便后续讲解

前面定义的 BikeFactoryBean 类上面直接添加了@Component注解,这样spring会默认以类名首字母小写(bikeFactoryBean)作为beanName;如果使用@Bean进行注册时,spring默认会以方法名作为beanName,下面继续以“BikeFactoryBean”为例。

spring容器启动过程中,在执行完所有的BeanFactoryPostProcessor,BeanPostProcessor以及注册Listener后会执行org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization()方法,此方法会对剩下所有的非Abstract、非LazyInit的单实例Bean进行实例化,以下为部分代码片段。

@Override public void preInstantiateSingletons() throws BeansException { ...省略代码... // 1. 拷贝一份副本:spring容器中的所有的Bean名称 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // 2. 遍历每一个beanName,尝试通过getBean()方法进行实例化 // 在getBean()方法内部会先尝试从容器singletonObjects中获取Bean,如果没有才会进行实例化操作 for (String beanName : beanNames) { // 3. 通过beanName获取Bean定义信息 BeanDefinition RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 4. 根据BeanDefinition判断该Bean是否不是抽象的,单例的,非懒加载的 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 5. 满足上面的条件后,在根据beanName判断此Bean是否是一个工厂Bean(实现了FactoryBean接口) if (isFactoryBean(beanName)) { // 6. 如果是一个工厂Bean,则在此处进行工厂Bean本身的实例化 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); ...省略代码... } else { // 如果不是工厂bean,也是调用getBean()方法进行实例化 getBean(beanName); } } } ...省略代码... }

preInstantiateSingletons()是在finishBeanFactoryInitialization()方法内部调用的

根据上面的代码流程,在第6步时,会对BikeFactoryBean类本身进行实例化,并且可以看出传递的beanName为初始注册的name前添加了&符前缀即&bikeFactoryBean,用于在genBean()方法内部标识它是一个工厂Bean。但是在跟踪源码后发现,在getBean()方法内部,会先将传入的beanName(&bikeFactoryBean)开头的&符去除,并且最终实例化Bean后,在容器中保存的beanName还是不带&符前缀的名称即bikeFactoryBean

根据第一步的结果,spring容器在启动后,工厂Bean会像普通Bean一样在spring容器中会保留一条自身的单实例Bean(spring容器中保存的数据为:<bikeFactoryBean, BikeFactoryBean>),既然spring容器中只保存了BikeFactoryBean本身,那么后续获取Bike类的beanName和Bean实例时,又是怎么获取到的呢?带着疑问,我们继续看后面的代码。首先,上面的例子中调用了applicationContext.getBeanNamesForType(Bike.class)方法来获取Bike类的beanName。所以继续跟踪此方法看看到底发生了什么。

// getBeanNamesForType()方法内部最终调用了此方法,可断点跟踪至此 private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { // 用来保存符合条件的结果(beanName集合) List<String> result = new ArrayList<>(); // 与上面的代码相似,遍历spring容器中注册的所有的beanNames for (String beanName : this.beanDefinitionNames) { if (!isAlias(beanName)) { try { // 根据beanName获取Bean的定义信息 BeanDefinition RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 根据BeanDefinition 进行检查 if (!mbd.isAbstract() && (allowEagerInit || (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) && !requiresEagerInitForType(mbd.getFactoryBeanName()))) { // 根据beanName和Bean的定义信息判断是否是工厂Bean boolean isFactoryBean = isFactoryBean(beanName, mbd); BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); boolean matchFound = (allowEagerInit || !isFactoryBean || (dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) && (includeNonSingletons || (dbd != null ? mbd.isSingleton() : isSingleton(beanName))) && // 根据Bean的定义信息判断完后,在此方法中判断此beanName对应的Bean实例是否与传入的类型相匹配 isTypeMatch(beanName, type); // 如果根据beanName获得的是一个工厂Bean,并且与传入的类型不匹配,则满足条件,将beanName添加 & 符前缀 if (!matchFound && isFactoryBean) { // 对于工厂Bean,接下来尝试匹配工厂Bean实例本身 beanName = FACTORY_BEAN_PREFIX + beanName; matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type); } // 如果获取的Bean实例与传入的类型匹配,将beanName添加到结果集合中 if (matchFound) { result.add(beanName); } } } catch (CannotLoadBeanClassException ex) { // ...省略代码... } catch (BeanDefinitionStoreException ex) { // ...省略代码... } } } // ...省略代码... return StringUtils.toStringArray(result); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfxsg.html