深入探究 Spring 中 FactoryBean 注册服务的实现与原理
引言
在 Spring 框架里,FactoryBean
是一个强大且重要的特性。它允许开发者以一种更加灵活的方式来创建和管理 Bean 对象。FactoryBeanRegistrySupport
和 AbstractBeanFactory
这两个类在处理 FactoryBean
相关操作时扮演着关键角色,它们共同协作完成了 FactoryBean
的注册、对象创建以及缓存管理等功能。接下来,我们将深入剖析这些类的实现细节和背后的设计理念。
1. 核心接口:FactoryBean
1.1 接口定义
interface FactoryBean<T> {T getObject() throws Exception;Class<?> getObjectType();boolean isSingleton();
}
1.2 详细解释
getObject()
方法:这是FactoryBean
最核心的方法,它负责创建并返回具体的 Bean 对象。开发者可以在这个方法中编写复杂的对象创建逻辑,比如进行对象的初始化、依赖注入、资源加载等操作。例如,在一个数据库连接池的FactoryBean
实现中,getObject()
方法可以创建并初始化一个数据库连接池实例。getObjectType()
方法:该方法用于返回getObject()
方法所创建对象的类型。Spring 框架在运行时可以通过这个方法获取对象的类型信息,从而进行类型检查和转换。比如,在进行 Bean 注入时,Spring 可以根据getObjectType()
返回的类型来判断是否符合注入要求。isSingleton()
方法:此方法用于指示FactoryBean
创建的对象是否为单例。如果返回true
,则表示该对象是单例的,Spring 会对其进行缓存,后续的请求都会返回同一个对象实例;如果返回false
,则每次请求都会调用getObject()
方法创建一个新的对象实例。
2. 基础支撑:DefaultSingletonBeanRegistry
2.1 类定义
class DefaultSingletonBeanRegistry {private final ConcurrentMap<String, Object> singletonObjects = new ConcurrentHashMap<>();protected Object getSingleton(String beanName) {return singletonObjects.get(beanName);}protected void addSingleton(String beanName, Object singletonObject) {singletonObjects.put(beanName, singletonObject);}
}
2.2 详细解释
singletonObjects
缓存:这是一个ConcurrentHashMap
,用于存储单例 Bean 对象。使用ConcurrentHashMap
可以确保在多线程环境下对单例对象的访问是线程安全的,避免了并发访问时可能出现的数据不一致问题。getSingleton(String beanName)
方法:该方法用于从singletonObjects
缓存中获取指定名称的单例 Bean 对象。如果缓存中存在该对象,则直接返回;如果不存在,则返回null
。addSingleton(String beanName, Object singletonObject)
方法:此方法用于将一个单例 Bean 对象添加到singletonObjects
缓存中。通过这种方式,Spring 可以在后续的请求中直接从缓存中获取该对象,而无需再次创建,提高了性能。
3. 关键类:FactoryBeanRegistrySupport
3.1 类定义
abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {private static final Object NULL_OBJECT = new Object();/*** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object*/private final ConcurrentMap<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>();protected Object getCachedObjectForFactoryBean(String beanName) {Object object = this.factoryBeanObjectCache.get(beanName);return (object != NULL_OBJECT ? object : null);}protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName) {if (factory.isSingleton()) {Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {object = doGetObjectFromFactoryBean(factory, beanName);this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));}return (object != NULL_OBJECT ? object : null);} else {return doGetObjectFromFactoryBean(factory, beanName);}}private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) {try {return factory.getObject();} catch (Exception e) {throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);}}
}
3.2 详细解释
3.2.1 factoryBeanObjectCache
缓存
这是一个专门用于缓存由 FactoryBean
创建的单例对象的 ConcurrentMap
。键为 FactoryBean
的名称,值为 FactoryBean
创建的对象。使用这个缓存可以避免重复创建单例对象,提高性能。
3.2.2 getCachedObjectForFactoryBean(String beanName)
方法
该方法用于从 factoryBeanObjectCache
缓存中获取指定名称的 FactoryBean
创建的对象。如果缓存中存在该对象,则直接返回;如果缓存中存储的是 NULL_OBJECT
,则表示该对象不存在,返回 null
。
3.2.3 getObjectFromFactoryBean(FactoryBean<?> factory, String beanName)
方法
这是一个核心方法,用于从 FactoryBean
中获取对象。如果 FactoryBean
创建的是单例对象,则先从 factoryBeanObjectCache
缓存中查找。如果缓存中不存在,则调用 doGetObjectFromFactoryBean
方法创建对象,并将其放入缓存中。如果 FactoryBean
创建的不是单例对象,则直接调用 doGetObjectFromFactoryBean
方法创建对象。
3.2.4 doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName)
方法
该方法直接调用 FactoryBean
的 getObject()
方法来创建对象。如果创建过程中出现异常,则抛出 BeansException
异常,将异常信息和原始异常一起封装,方便后续的错误处理和调试。
4. 核心抽象类:AbstractBeanFactory
4.1 类定义
abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {protected <T> T doGetBean(final String name, final Object[] args) {Object sharedInstance = getSingleton(name);if (sharedInstance != null) {// 如果是 FactoryBean,则需要调用 FactoryBean#getObjectreturn (T) getObjectForBeanInstance(sharedInstance, name);}BeanDefinition beanDefinition = getBeanDefinition(name);Object bean = createBean(name, beanDefinition, args);return (T) getObjectForBeanInstance(bean, name);}private Object getObjectForBeanInstance(Object beanInstance, String beanName) {if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}Object object = getCachedObjectForFactoryBean(beanName);if (object == null) {FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;object = getObjectFromFactoryBean(factoryBean, beanName);}return object;}protected abstract BeanDefinition getBeanDefinition(String name);protected abstract Object createBean(String name, BeanDefinition beanDefinition, Object[] args);
}
4.2 详细解释
4.2.1 doGetBean(String name, Object[] args)
方法
这是获取 Bean 对象的核心方法。首先,它尝试从单例缓存中获取指定名称的 Bean 对象。如果缓存中存在该对象,则调用 getObjectForBeanInstance
方法进行处理,因为该对象可能是一个 FactoryBean
,需要进一步获取其创建的对象。如果缓存中不存在该对象,则通过 getBeanDefinition
方法获取该 Bean 的定义信息,再调用 createBean
方法创建对象,最后同样调用 getObjectForBeanInstance
方法进行处理。
4.2.2 getObjectForBeanInstance(Object beanInstance, String beanName)
方法
该方法用于判断 beanInstance
是否为 FactoryBean
类型。如果不是,则直接返回该对象;如果是,则先从 factoryBeanObjectCache
缓存中获取 FactoryBean
创建的对象。如果缓存中不存在,则调用 getObjectFromFactoryBean
方法从 FactoryBean
中获取对象。
4.2.3 getBeanDefinition(String name)
和 createBean(String name, BeanDefinition beanDefinition, Object[] args)
方法
这两个方法是抽象方法,需要在具体的子类中实现。getBeanDefinition
方法用于根据 Bean 的名称获取其定义信息,这些定义信息包含了 Bean 的各种属性和配置;createBean
方法用于根据 Bean 的定义信息创建具体的 Bean 对象,可能涉及到对象的实例化、属性注入、初始化等操作。
5. 示例 FactoryBean 实现类
5.1 类定义
class ExampleFactoryBean implements FactoryBean<String> {@Overridepublic String getObject() throws Exception {return "Example Object";}@Overridepublic Class<?> getObjectType() {return String.class;}@Overridepublic boolean isSingleton() {return true;}
}
5.2 详细解释
这个类实现了 FactoryBean
接口,用于创建一个 String
类型的对象。getObject()
方法返回一个固定的字符串 "Example Object"
,表示创建的对象内容。getObjectType()
方法返回 String.class
,明确了创建对象的类型。isSingleton()
方法返回 true
,表示该对象是单例的,Spring 会对其进行缓存,后续的请求都会返回同一个 "Example Object"
实例。
6. 测试类
6.1 类定义
public class FactoryBeanRegistrationTest {public static void main(String[] args) {AbstractBeanFactory beanFactory = new AbstractBeanFactory() {@Overrideprotected BeanDefinition getBeanDefinition(String name) {return new BeanDefinition();}@Overrideprotected Object createBean(String name, BeanDefinition beanDefinition, Object[] args) {if ("exampleFactoryBean".equals(name)) {return new ExampleFactoryBean();}return null;}};String exampleObject = beanFactory.doGetBean("exampleFactoryBean", null);System.out.println(exampleObject);}
}
6.2 详细解释
在这个测试类中,我们创建了一个 AbstractBeanFactory
的匿名子类,并重写了 getBeanDefinition
和 createBean
方法。getBeanDefinition
方法简单地返回一个新的 BeanDefinition
实例,实际应用中可以根据具体需求从配置文件或其他数据源中获取 Bean
的定义信息。createBean
方法根据 beanName
判断是否为 "exampleFactoryBean"
,如果是,则返回 ExampleFactoryBean
实例;否则返回 null
。然后调用 doGetBean
方法获取 ExampleFactoryBean
创建的对象,并将其打印输出。通过这个测试,我们可以验证 FactoryBean
注册服务的功能是否正常。
7. 设计模式与应用场景
7.1 设计模式
- 工厂模式:
FactoryBean
接口本身就是工厂模式的一种体现。通过实现FactoryBean
接口,开发者可以将对象的创建逻辑封装在getObject()
方法中,使得对象的创建和使用分离,提高了代码的可维护性和可扩展性。 - 缓存模式:
FactoryBeanRegistrySupport
类中的factoryBeanObjectCache
缓存和DefaultSingletonBeanRegistry
类中的singletonObjects
缓存都运用了缓存模式。缓存模式可以避免重复创建对象,提高系统的性能和响应速度。
7.2 应用场景
- 复杂对象的创建:当需要创建的对象比较复杂,包含多个依赖项或需要进行复杂的初始化操作时,可以使用
FactoryBean
来封装对象的创建逻辑。例如,创建一个数据库连接池、线程池等。 - 动态对象的创建:如果需要根据不同的条件动态创建对象,可以在
FactoryBean
的getObject()
方法中编写动态创建逻辑。例如,根据配置文件中的参数创建不同类型的日志记录器。
8. 总结
通过对 FactoryBean
注册服务的深入分析,我们了解到 Spring 框架通过 FactoryBean
接口、FactoryBeanRegistrySupport
类和 AbstractBeanFactory
类的协作,提供了一种灵活、高效的对象创建和管理方式。FactoryBean
允许开发者自定义对象的创建逻辑,而 FactoryBeanRegistrySupport
负责对象的缓存和获取,AbstractBeanFactory
则在整个 Bean 生命周期中对 FactoryBean
进行了特殊处理。这种设计使得 Spring 框架能够满足各种复杂的应用场景,提高了系统的可维护性和可扩展性。在实际开发中,合理运用 FactoryBean
可以让我们更加灵活地管理对象的创建和使用,提升开发效率和代码质量。