Spring FactoryBean 源码分析
一、FactoryBean的作用
Spring 中有两种 bean ,一种是普通 bean ,另外一种则是 FactoryBean. 普通 bean 返回的是指定类的一个实例对象,而 FactoryBean 则不同,它返回的对象不是某一个指定类的实例对象,而是该 FactoryBean 的 getObject() 方法所返回的对象,创建出来的对象是单例还是多例,由 FactoryBean 的 isSingleton() 方法来控制.
一般情况下, Spring 通过获取 bean 标签中配置的 class 属性的全类名,通过反射(Class.forName(String className)来创建 bean 对象,但是在某些情况下,有一些 bean 的实例化过程比较复杂,如果按照传统的方式,则需要在 <bean...> 标签中配置大量的信息,配置方式的灵活性是受限制的,这个时候通过获取配置然后编码的方式来实例化 bean,可能只会得到一个简单的方案,不能满足我们实际的需求,为了解决这个问题, Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口,通过该接口实现类中的 getObject() 方法私人订制 bean 的实现逻辑,这样就大大的增加了灵活性.同时这样也可以隐藏实例化 bean 的一些复杂的细节,给上层的调用带来了便利.
二、FactoryBean的使用特点
实现了 FactoryBean 接口的 bean 如果通过配置的 id 去获取,获取到的是 FactoryBean 调用 getObject()方法返回的对象,而不是FactoryBean 本身,如果想要获取到 FactoryBean 本身,需要在 id前面加上一个 & 符号,例如:
1 | applicationContext.getBean( "&id" ) |
三、FactoryBean 案例演示
1、FactoryBean 接口的实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // 自定义类 Person 实现 FactoryBean 接口 public class Person implements FactoryBean<Mango> { @Override public Mango getObject() throws Exception { Mango mango = new Mango(); mango.setName( "mango" ); mango.setColor( "yellow" ); mango.setColor( "10.0" ); return mango; } @Override public Class<?> getObjectType() { return null ; } @Override public boolean isSingleton() { // 返回值是 true,代表创建的 Mango 对象是单例的,反之为多例 return true ; } } |
2、spring 配置文件(classpath:spring-config/spring-ioc.xml 配置文件)
1 2 3 4 5 6 7 8 | <?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= "person" class = "com.xiaomaomao.entity.Person" ></bean> </beans> |
3、测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class SpringTest { public static void main(String[] args) { ApplicationContext ioc = new ClassPathXmlApplicationContext( "classpath:spring-config/spring-ioc.xml" ); // 获取到的是 FactoryBean 本身实例对象 Object person01 =ioc.getBean( "&person" ); // 获取到的是 FactoryBean 调用 getObject() 方法返回的对象 Object person02 = ioc.getBean( "person" ); Object person03 = ioc.getBean( "person" ); // 输出 FactoryBean 本身实例对象 System.out.println(person01); // 输出 FactoryBean 调用 getObject() 方法返回的对象 System.out.println(person02); // 判断 FactoryBean 调用 getObject() 方法返回的对象是不是单例 System.out.println(person02 == person03); } } |
4、测试结果
通过测试结果,我们可以得出以下结论:
(1)、getBean("&id") 获取到的是 FactoryBean 本身对象
(2)、getBean("id") 获取到的是 FactoryBean 调用 getObject() 方法返回的对象
(3)、isSingleton() 方法可以控制 FactoryBean 调用 getObject() 方法返回的对象是单例还是多例
四、FactoryBean 的实际应用
就拿 Mybatis 来说吧,我们也是通过注入一个 SqlSessionFactoryBean ,实际上使用的却是 SqlSessionFactoryBean 对象通过调用 getObject() 方法返回的 SqlSessionFactory 对象.
1 2 3 4 5 6 | <!-- spring 和 MyBatis 整合,不需要 mybatis 的配置映射文件 --> <bean id= "sqlSessionFactory" class = "org.mybatis.spring.SqlSessionFactoryBean" > <property name= "dataSource" ref= "dataSource" /> <!-- 自动扫描 mapping.xml 文件 --> <property name= "mapperLocations" value= "classpath:mapper/*.xml" ></property> </bean> |
五、FactoryBean 源码解析
说到这里就简单说一下 FactoryBean 的初始化和获取 IOC 中的 bean 的过程吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | // DefaultListableBeanFactory 类中的方法,代码行号: 728 public void preInstantiateSingletons() throws BeansException { if ( this .logger.isDebugEnabled()) { this .logger.debug( "Pre-instantiating singletons in " + this ); } // 这里的 this 代表的是 DefaultListableBeanFactory // 这个类里面封装了 spring 配置文件中所有,bean 标签的配置信息 List<String> beanNames = new ArrayList<String>( this .beanDefinitionNames); // 触发所有非懒加载的单例 bean 的初始化动作 for (String beanName : beanNames) { // 合并父 bean 的配置 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 非懒加载、非抽象的单例 bean if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 判断当前 bean 是否是 FactoryBean (我们配置的 person 这个 bean 由于实现了 FactoryBean 这个接口 // 所以它属于 FactoryBean if (isFactoryBean(beanName)) { // FactoryBean 的初始化动作,这里的 FACTORY_BEAN_PREFIX 是一个前缀 & final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged( new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { // 普通 bean 的初始化 getBean(beanName); } } } // 到这里为止,我们所说的非懒加载非抽象的所有 singleton bean 已经初始化完毕 // 如果我们定义的 bean 实现了 SmartInitializingSingleton 这个接口,那么会在这里回调 for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null ) { AccessController.doPrivileged( new PrivilegedAction<Object>() { @Override public Object run() { smartSingleton.afterSingletonsInstantiated(); return null ; } }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } } |
由于我们在 Spring 的配置文件中配置的 bean 是一个 FactoryBean ,所以我们点进去 (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName) 这个方法看一下,这个方法的参数是 &person (person 这个是 id ,我们在配置文件中配置的,解析 XML 的时候,这个 id 就赋值给了我们这里的 beanName)
1 2 3 4 | // AbstractBeanFactory 类中的方法,代码行号: 196 public Object getBean(String name) throws BeansException { return doGetBean(name, null , null , false ); } |
同时可以看一下下面几个重载的方法,这个几个方法是我们获取 IOC 容器中 bean 的一些方法,当然上面那个方法既可以初始化 bean,也可以获取 IOC 容器中的 bean 对象
1 2 3 4 5 6 7 8 9 10 11 12 | // 获取 bean 的时候 ioc.getBean("person",Person.class) public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null , false ); } // 获取 bean 的时候 ioc.getBean("person","xiaomao") public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null , args, false ); } // 获取 bean 的时候 ioc.getBean("person", Person.class,"xiaomao","xiaomaomao") public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException { return doGetBean(name, requiredType, args, false ); } |
不管是初始化 bean 还是获取 IOC 容器中的 bean ,我们都最终会调用 doGetBean(....) 这个方法,只是不同的需求下传入的参数值不同而已.点进去这个方法,看看里面到底有什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | // AbstractBeanFactory 类中的方法,代码行号: 235 protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { // 对于普通的 bean,不管是初始化 bean 还是获取 bean, beanName 的值是不会有变化的,自始至终都是一样 // 而对于 FactoryBean 来说,初始化 bean 的时候,由于传进来的参数 name 是带有 & 符号的,例如 &person // 这里是想真正的获取到 FactoryBean 的 beanName ,所以会去掉 & 符号 final String beanName = transformedBeanName(name); // 这个要关注一下,创建 bean 、获取 bean 的返回值 Object bean; // 判断父容器中是否已经创建过了该单例 bean // 第一次初始化的时候,这里是没有创建过该单例 bean 的,所以值为 null // 如果是后面通过 getBean(...) 来获取的 bean 实例的时候,因为初始化已经创建了 bean ,所以这里就不会为 null Object sharedInstance = getSingleton(beanName); // 如果没有创建该 singleton bean ,并且传入的参数为 null ,那么执行获取 bean 的操作 // 如果获取 bean 实例的时候,传入了 args 参数,因为已经创建过了该 bean 实例,所以 sharedInstance 不为 null // 这个时候如果传入的 args 参数不为 null ,那么就不满足该条件,这里就不是 获取 bean 了,而是需要创建 bean // 例如: ioc.getBean("person","xiaomao") ,这种情况会跳到下面的 else 分支中,就不是获取 bean,而是创建 bean if (sharedInstance != null && args == null ) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug( "Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference" ); } else { logger.debug( "Returning cached instance of singleton bean '" + beanName + "'" ); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null ); } // 执行创建 bean 的操作 // 如果我们通过 getBean(beanName,args) 传入了 args 参数,那么我们就不是获取 bean 了,而是要创建 bean else { // 如果已经创建了该 beanName 的 prototype ,那么抛出异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 检查是否这个 BeanDefinition 对象已经存在父容器中了 BeanFactory parentBeanFactory = getParentBeanFactory(); // 如果自身容器中不存在,父容器中存在该 BeanDefiniton if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (args != null ) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } // 标记已经创建了这个 bean if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null ) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'" ); } registerDependentBean(dep, beanName); getBean(dep); } } // 创建 bean 实例对象 if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { // 创建 bean 对象,核心方法...(我们这里就不看了,还是蛮多的) return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); // 如果是普通 bean ,返回自身对象 // 如果是 FactoryBean 返回自身对象,而不是调用 getObject() 方法返回的对象 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null ; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); final Scope scope = this .scopes.get(scopeName); if (scope == null ) { throw new IllegalStateException( "No Scope registered for scope name '" + scopeName + "'" ); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton" , ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug( "Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" , ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; } |
看一下这个方法,虽然比较长,我们只关心我们需要的部分,上面这个方法不管最后执行哪一个分支,最终都会调用 bean = getObjectForBeanInstance(...) 这个方法,点进去看吧.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | // AbstractBeanFactory 类中的方法,代码行号: 1607 protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // 两个判断条件 // BeanFactoryUtils.isFactoryDereference(name):判断 name 是否不为空,并且以 & 开头 // beanInstance instanceof FactoryBean:当前 bean 是否是 FactoryBean 的实现类 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } // 初始化的时候,如果是 FactoryBean ,那么上述两个判断条件都是成立的,直接返回一个 beanInstance 对象 // 获取对象的时候,如果通过 ioc.getBean("&person") 这种方式,那么也是直接返回一个 beanInstance 对象 // 这里的 beanInstance 是我们在 AbstractBeanFactory 类中通过调用 createBean(beanName, mbd, args) // 方法创建的,它是一个 Person 类的对象,不是 FactoryBean 实现类调用 getObject() 方法生产的对象 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } // 如果是已经初始化完毕了,去 IOC 容器中获取 bean 实例对象的时候 // 如果通过 ioc.getBean("person") 获取 bean 实例对象,会执行如下代码 Object object = null ; if (mbd == null ) { object = getCachedObjectForFactoryBean(beanName); } if (object == null ) { // beanInstance 是 Person 对象,而 Person 又是实现了 FactoryBean 接口的 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); // 获取 FactoryBean 的核心方法.... object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } |
从上面代码我们知道, ioc.get("&person") 获取到的是 Person 类对象,如果我们要获取 Person 对象调用 getObject() 方法生产的 Mango 对象,该如何获取呢?
找到 getObjectFromFactoryBean(...) 方法,点进去看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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 ) { // FactoryBean 调用 getObject() 方法生产的对象 object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this .factoryBeanObjectCache.get(beanName); if (alreadyThere != null ) { object = alreadyThere; } else { if (object != null && shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed" , ex); } } this .factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT)); } } return (object != NULL_OBJECT ? object : null ); } } else { // FactoryBean 调用 getObject() 方法生产的对象 Object object = doGetObjectFromFactoryBean(factory, beanName); if (object != null && shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed" , ex); } } return object; } } |
细节就不看了,有一点是很明显的,不管判断条件如何,都会进入到 doGetObjectFromFactoryBean(factory, beanName) 这个方法里面,继续点进去看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | private Object doGetObjectFromFactoryBean( final FactoryBean<?> factory, final String beanName) throws BeanCreationException { Object object; try { if (System.getSecurityManager() != null ) { AccessControlContext acc = getAccessControlContext(); try { object = AccessController.doPrivileged( new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { return factory.getObject(); } }, acc); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 这里的 factory 就是 FactoryBean 实现类对象,我们这里就是 Person 类对象 // 根据继承的关系,子类中实现了 getObject() 方法,那么实际调用的就是子类里的 getObject()方法 // 也就是我们 Person 对象中的 getObject() 方法 object = factory.getObject(); } } catch (FactoryBeanNotInitializedException ex) { throw new BeanCurrentlyInCreationException(beanName, ex.toString()); } catch (Throwable ex) { throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation" , ex); } // Do not accept a null value for a FactoryBean that's not fully // initialized yet: Many FactoryBeans just return null then. if (object == null && isSingletonCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException( beanName, "FactoryBean which is currently in creation returned null from getObject" ); } // 将BeanFactory 实现类对象通过调用 getObject() 方法生产的对象返回出去. return object; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?