- 先抛出面试经常问的问题 FactoryBean 和 BeanFactory的区别?
相同点:都是用来创建对象的。
不同点:
①当使用BeanFactory的时候必须要遵循完整的创建过程,这个过程是由spring来管理控制的。
②而使用FactoryBean只需要调用getObject就可以返回具体的对象,整个对象的创建过程是由用户自己来控制的,更加灵活
③FactoryBean对象和FactoryBean的getObject创建出来的对象都交到BeanFactory管理 - spring在管理FactoryBean实际上是管理了几个对象?
实际上是两个对象
其中FactoryBean的getObject 方法创建的对象是放factoryBeanObjectCache里面的 - 代码示例:
package com.zhangfuyin.factoryBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Component; /** * @author lenovo */ @Component public class MyFactoryBean implements FactoryBean<BeanObj> { @Override public BeanObj getObject() throws Exception { return new BeanObj(); } @Override public Class<?> getObjectType() { return BeanObj.class; } @Override public boolean isSingleton() { return true; } }
- 如何从spring容器中获取FactoryBean的getObject对象?如何从或FactoryBean对象呢?
获取getObject对象:Object factoryBeanObj = ac.getBean("myFactoryBean");
获取FactoryBean对象通过取地址符(后面源码分析都会看到具体源码):MyFactoryBean factoryBean = (MyFactoryBean)ac.getBean("&myFactoryBean");
- 在spring容器中BeanDefinition存储的FactoryBean的bean定义信息
for (String beanName : beanNames) { // 合并的bd实际上就是RootBeanDefinition,在Spring中没有MergedBeanDefinition类,而有MergedBeanDefinitionPostProcessor RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 如果不是抽象的、是单例且不是懒加载的 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { // 如果bean是FactoryBean类型,则需要获取原来的bean对象,需要在beanName前加一个"&"符号 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 { // 如果bean不是FactoryBean类型,直接调用getBean去创建bean(大多数场景都会直接进到这个else代码块) getBean(beanName); } } }
这里如果bean的定义信息是FactoryBean的时候 加上"&"取地址符去创建信息
- 创建FactoryBean对象 这里不在详细说明 主要看doCreateBean方法、最终FactoryBean对象会被放到一级缓存里面去
- 如何获取FacoryBean对象和FactoryBean创建得对象和普通Bean对象
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { object = doGetObjectFromFactoryBean(factory, beanName); // Only post-process and store if not put there already during getObject() call above // (e.g. because of circular reference processing triggered by custom getBean calls) Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { object = alreadyThere; } else { if (shouldPostProcess) { if (isSingletonCurrentlyInCreation(beanName)) { // Temporarily return non-post-processed object, not storing it yet.. return object; } beforeSingletonCreation(beanName); try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally { afterSingletonCreation(beanName); } } if (containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); } } } return object; } } else { // 这里的方法很关键,看见do打头的就知道是真正干活的,下面就是要通过factoryBean定制化beanName对应的实例 Object object = doGetObjectFromFactoryBean(factory, beanName); if (shouldPostProcess) { try { // 由于object是走的是FactoryBean的定制方法 // 因此postProcessBeforeInitialization的方法是不会被调用了 // 但是postProcessAfterInitialization方法会被调用,也就是bean初始化后做一些事情 object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } return object; } }
①如果要取得对象名称有“&”取地址符 直接把普通缓存的FactoryBean对象返回
②如果没有取地址符 如果不是FactoryBean类型 那么就是普通对象 直接返回普通对象
③如果factoryBeanObjectCache有对象 那么将返回 否则调用FactoryBeanFactoy.getObject
返回对象返回、并且放入factoryBeanObjectCache中
2、Spring源码之FactoryBean
于 2022-12-05 18:29:27 首次发布