程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Spring

    • Spring6 - 概述
    • Spring6 - 入门
    • Spring6 - IOC(基于XML)
    • Spring6 - IOC(基于注解)
    • spring6 - FactoryBean
      • 1. FactoryBean
        • FactoryBean 接口源码
        • FactoryBean 底层源码
        • FactoryBean 到底能干什么
        • 1. 动态创建对象
        • 2. 对象的装配和初始化
        • 3. 对象的代理和包装
        • 4. 对象的缓存和复用
        • 5. 对象的延迟初始化
        • 6. 对象的销毁和资源释放
      • 2. BeanFactory
        • 有了BeanFactory的定义,用户可以执行以下操作:
        • BeanFactory接口源码
    • Spring6 - Bean的作用域
    • Spring6 - Bean生命周期
    • Spring6 - Bean循环依赖
    • Spring6 - 手写IOC容器
    • Spring6 - AOP
    • Spring6 - 自定义注解
    • Spring6 - Junit
    • Spring6 - 事务
    • Spring6 - Resource
    • Spring6 - 国际化
    • Spring6 - 数据校验
    • Spring6 - Cache
    • Spring集成Swagger2
  • Spring生态
  • Spring
scholar
2024-04-02
目录

spring6 - FactoryBean

在Spring中,有两个很容易混淆的类:BeanFactory和FactoryBean。前者是Factory也就是IOC容器或对象工厂,后者是Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对于FactoryBean而言,这个Bean不是简单的Bean,而是一个能产生或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

BeanFactory:Bean工厂,是一个工厂(Factory),我们Spring IoC容器的最顶层接口就是这个BeanFactory,它的作用是管理Bean,即实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

FactoryBean:工厂Bean,是一个Bean,作用是产生其他bean实例。通常情况下,这种bean没有什么特别的要求,仅需要提供一个工厂方法,该方法用来返回其他bean实例。通常情况下,bean无须自己实现工厂模式,Spring容器担任工厂角色;但少数情况下,容器中的bean本身就是工厂,其作用是产生其它bean实例。

FactoryBean是一个编程协议,实现不应该依赖于注解驱动的注入或其他反射功能。

获取FactoryBean的方法是getBean("&"+beanName); 就是在beanName加个"&"前缀,若直接getBean(beanName),获取到的是FactoryBean通过getObject接口生成的Bean。

# 1. FactoryBean

FactoryBean 在 Spring 框架中用于生成特定类型的 bean 实例,与普通 bean 的定义方式相比,FactoryBean 提供了更高的灵活性,允许程序在运行时动态地创建复杂对象。这种方式特别适合于创建那些需要大量配置并且复杂度较高的 bean 实例。

下面是一个 FactoryBean 的实现示例,用于动态创建 Car 类型的对象:

import org.springframework.beans.factory.FactoryBean;

// 实现 FactoryBean 接口,指定泛型为 Car,表示这个工厂 Bean 创建的对象类型为 Car
public class CarFactoryBean implements FactoryBean<Car>{

    // Car 对象的属性
	private String brand;
	
    // 设置 Car 品牌的 setter 方法,允许通过配置设置品牌属性
	public void setBrand(String brand) {
		this.brand = brand;
	}
	
    // getObject() 方法是 FactoryBean 接口的核心方法,用于返回一个 Car 实例
	public Car getObject() throws Exception {
		return new Car(brand, 500000.0); // 创建一个 Car 对象并返回
	}

    // getObjectType() 方法返回 FactoryBean 创建的对象类型
	public Class<?> getObjectType() {
		return Car.class; // 返回 Car 类型
	}

    // isSingleton() 方法指定该 FactoryBean 创建的对象是否为单例
	public boolean isSingleton() {
		return false; // 返回 false,表示每次调用 getObject() 时都创建一个新的实例
	}
}
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

# FactoryBean 接口源码

实现该接口的bean,将会被作为一个工厂用来暴露某个对象(不是暴露自己哦)。当然,实现了该接口的bean也可以被作为一个正常bean。FactoryBean是以bean样式定义的,但是其getObject()方法暴露的对象是其创建的对象,通常非自身。

public interface FactoryBean<T> {
    
   //属性类型,可以在BeanDefinition中被AttributeAccessor#setAttribute方法设置,
   //以便工厂bean在无法从工厂bean类推导出对象类型时,可以发出其对象类型的信号
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
    
    // 获取由此工厂创建的对象实例
    T getObject() throws Exception;

    // 获取由此工厂创建的对象实例的类型
    Class<?> getObjectType();

    // 判断由此工厂创建的对象实例是否为单例模式
    default boolean isSingleton() {
        return true;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

FactoryBean<T> 接口在 Spring 框架中扮演着特殊而且重要的角色。它不同于常规的 Bean,因为 FactoryBean 本身被定义为一个工厂,它的主要职责是生产其他 Bean 实例。而这些生产出的 Bean 实例可以是单例(Singleton)也可以是原型(Prototype),还可以根据实际需求在创建时进行延迟加载(懒加载)。

主要方法及其作用

  • getObject():该方法返回 FactoryBean 创建的对象实例。这个方法支持 Singleton 和 Prototype 作用域的对象。从 Spring 2.0 开始,FactoryBeans 允许返回 null 对象,表示空的 Bean 实例。

  • getObjectType():返回 FactoryBean 创建的对象的类型。如果在调用时对象的类型不确定,则可能返回 null。这个方法允许 Spring 在不实例化对象的情况下,检查 Bean 是否匹配特定的类型,这在自动注入时非常有用。

  • isSingleton():指示 FactoryBean 管理的对象是否为单例。如果是,意味着 getObject() 方法返回的每次都是相同的对象实例。

`FactoryBean` 接口的特点和用法

  • 作为 Bean 的工厂:实现了 FactoryBean 接口的类,不会直接作为普通 Bean 注册到 Spring 容器中。相反,它们作为工厂使用,getObject() 方法返回的对象才是真正注册到 Spring 容器中的 Bean。

  • 支持 Singleton 和 Prototype:FactoryBean 可以根据需要在启动时创建对象,或者在实际需要时才实例化对象(懒加载)。通过 isSingleton() 方法指定。

  • 用于复杂对象的创建:在 Spring 的内部使用非常广泛,例如用于创建 AOP 的代理对象(ProxyFactoryBean)或是用于 JNDI 对象的查找(JndiObjectFactoryBean)等。也可以用于用户自定义组件,特别是那些需要复杂初始化过程的 Bean。

  • 与容器的交互:FactoryBean 实现不应依赖于注解驱动的注入或其他反射功能。getObjectType() 和 getObject() 方法可能会在应用的早期,甚至在任何后置处理器设置之前就被调用。

# FactoryBean 底层源码

我们都知道在Spring中我们的Bean都会被Spring的IOC容器所管理,在AbstractApplicationContext中有一个很重要的方法:refresh,项目启动或重启的时候refresh会调用getBean初始化所有的Bean,这个getBean最终会指向AbstractBeanFactory中的getBean方法。

在AbstractBeanFactory中,不管是根据名称还是根据类型,getBean最终都会调用doGetBean,doGetBean 方法是获取 bean 实例的核心逻辑,它负责处理直接实例化的 bean 和通过 FactoryBean 创建的 bean 实例。

protected Object doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    final String beanName = transformedBeanName(name);
    Object sharedInstance = getSingleton(beanName);

    // transformedBeanName 方法用于获取 bean 的真正名称,如果 bean 名称前面有 "&",它会被移除
    // 这是因为 "&" 前缀在 Spring 中用于引用 FactoryBean 本身,而不是它创建的对象

    // getSingleton 方法尝试从缓存中获取一个单例 bean 的实例
    // 这个缓存是在 BeanFactory 的实现中维护的,如 DefaultSingletonBeanRegistry 类中的 singletonObjects
    
    // 下面的逻辑会检查 sharedInstance 是否已经存在,如果不存在,会根据 bean 的定义来创建实例
    // 如果这个 bean 是通过 FactoryBean 创建的,则会调用 FactoryBean 的 getObjectForBeanInstance 方法来获取 bean 实例

    // 此处代码省略...
    
    return sharedInstance;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 获取 Bean 的实际名称:通过调用 transformedBeanName 方法获取 Bean 的真正名称。如果 Bean 名称前面有 & 前缀,这个前缀会被移除。这是因为在 Spring 中,& 前缀用于引用 FactoryBean 本身,而不是它创建的对象。
  • 尝试从缓存中获取单例 Bean 的实例:使用 getSingleton 方法尝试从 BeanFactory 的单例缓存中获取 Bean 实例。这个缓存是在 BeanFactory 的实现中维护的,例如 DefaultSingletonBeanRegistry 类中的 singletonObjects。
  • 处理 FactoryBean 的情况:如果得到的 Bean 实例是 FactoryBean 的实例,doGetBean 方法会通过 FactoryBean 的 getObjectForBeanInstance 方法来创建 Bean 实例。

在doGetBean方法中,拿到sharedInstance后,后面的一大堆操作做了单例、多例等判断,最终会走到getObjectForBeanInstance方法,关键部分就在这个方法中,进入方法代码。






 



 



















 




protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

    // 判断是否需要返回 FactoryBean 本身而不是它创建的对象
    // 如果 Bean 名称以 '&' 开头,那么它表示的是对 FactoryBean 实例本身的直接引用
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
        }
        return beanInstance;
    }

    // 如果 Bean 实例不是 FactoryBean,直接返回这个实例
    if (!(beanInstance instanceof FactoryBean)) {
        return beanInstance;
    }
    
    // 如果是 FactoryBean,则需要调用 FactoryBean#getObject 方法获取 Bean 实例
    Object object = getCachedObjectForFactoryBean(beanName);
    if (object == null) {
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // 判断是否需要同步访问
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}
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

在上面的代码中有两个判断分别是beanInstance instanceof FactoryBean和BeanFactoryUtils.isFactoryDereference(name),前面判断的是beanInstance是否属于FactoryBean或其子类的实例,后面这个方法判断name是否不为空且以&开头。

public static boolean isFactoryDereference(@Nullable String name) {
        return name != null && name.startsWith("&");
    }
1
2
3

如果beanInstance不属于FactoryBean或其子类的实例,或者name是以&开头就直接返回实例对象beanInstance,否则进入到if分支中。在if分支里的各种if xx ==null判断是为了提高性能,咱们只挑关键部分看:object = getObjectFromFactoryBean(factory, beanName, !synthetic); 继续跟踪进去看代码。








 


















































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 获取对象
                object = doGetObjectFromFactoryBean(factory, beanName);
                // 再次检查缓存,防止在 doGetObjectFromFactoryBean 中已经被其他线程处理
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere; // 如果已经存在,则使用缓存中的对象
                }
                else {
                    // 如果需要后处理
                    if (shouldPostProcess) {
                        // 如果当前单例正在创建中,则直接返回对象,不进行缓存
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            return object;
                        }
                        // 否则,进行单例创建前的处理
                        beforeSingletonCreation(beanName);
                        try {
                            // 对从 FactoryBean 获取的对象进行后处理
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
                            // 单例创建后的处理
                            afterSingletonCreation(beanName);
                        }
                    }
                    // 如果这个 beanName 的单例仍然存在,则将处理后的对象放入缓存
                    if (containsSingleton(beanName)) {
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            return object; // 返回最终处理过的对象
        }
    }
    else {
        // 对于非单例的情况,直接通过 FactoryBean 获取对象,并根据需要进行后处理
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}
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

这里面也是做了很多判断,咱们也只挑关键部分看,这里说一下个人想法:

看源码的技巧

看源码的时候如果我们一直追究所有的细节那会让我们会越陷越深,掉入细节的无底洞,稍不留神脑回路跟不上就会蒙圈。我们要学会找源码中的关键部分看,弄懂主要流程和本次看源码的目的的那部分就行。等我们对Spring整体有了一个很好的理解之后,再回头看之前不懂的代码就会豁然开朗。

在上面这个方法中不管是走上面的if分支还是到下边的else中,关键部分就是doGetObjectFromFactoryBean(factory, beanName)这段代码调用,继续点进去。




 
 



























private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
    Object object;
    try {
        // 尝试从 FactoryBean 获取对象实例
        object = factory.getObject();
    }
    catch (FactoryBeanNotInitializedException ex) {
        // FactoryBean 尚未初始化完成时抛出异常
        // 抛出 BeanCurrentlyInCreationException 异常,表示当前的 Bean 正在创建中
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    }
    catch (Throwable ex) {
        // FactoryBean 在创建对象时抛出了其他异常
        // 抛出 BeanCreationException 异常,表示对象创建失败
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }

    // 如果从 FactoryBean 获取的对象为 null
    if (object == null) {
        // 如果当前 Singleton Bean 正在创建中,则抛出 BeanCurrentlyInCreationException 异常
        // 这是因为不接受 FactoryBean 在未完全初始化时返回 null 值的情况
        if (isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        // 如果 FactoryBean 返回 null,并且当前 Singleton Bean 不在创建中,则返回一个 NullBean 实例
        // NullBean 是一个特殊的占位符对象,用于表示 null 值
        object = new NullBean();
    }
    return object; // 返回从 FactoryBean 获取的对象实例,或者在特定情况下返回 NullBean 实例
}
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

在这个方法中有一行关键代码:object = factory.getObject(); 这个factory就是我们传入的beanInstance实例。绕了这么一大圈,getBean方法返回的居然是我们实现FactoryBean接口定义的getObject方法。

那么跟一开始对FactoryBean的描述印证了,FactoryBean是一个能生产或修饰对象生成的工厂Bean。一个Bean如果实现了FactoryBean接口,那么根据该Bean的名称获取到的实际上是getObject返回的对象,而不是这个Bean自身实例,如果要获取这个Bean自身实例,那么需要在名称前面加上'&'符号。

# FactoryBean 到底能干什么

FactoryBean允许我们在创建Bean实例时编写自定义的逻辑,并且可以通过其返回的实际Bean实例类型来实现更精细的依赖注入。同时,Spring框架还提供了一些内置的FactoryBean实现,例如ProxyFactoryBean和JndiObjectFactoryBean,可以帮助我们更方便地创建一些常见的Bean实例。

FactoryBean 是 Spring 框架中的一个接口,它可以创建和管理其他对象的实例。通过实现 FactoryBean 接口,可以自定义对象的创建过程,可以实现一些特殊的功能。

FactoryBean 主要有以下作用:

  1. 动态创建对象:FactoryBean 可以根据配置的参数和条件,动态地创建对象。这样可以根据不同的情况创建不同的对象实例。
  2. 对象的装配和初始化:FactoryBean 可以对创建的对象进行配置和初始化,可以通过设置不同的属性值或者调用不同的方法来进行装配和初始化。
  3. 对象的代理和包装:通过 FactoryBean 可以对创建的对象进行代理和包装,可以动态地增加或修改对象的功能。
  4. 对象的生命周期管理:FactoryBean 可以管理所创建的对象的生命周期,可以在对象创建前后执行一些操作,可以在需要时销毁对象。
  5. 对象的缓存和复用:FactoryBean 可以实现对象的缓存和复用,可以避免重复创建对象,提高性能。

下面给出几种常见的 FactoryBean 的使用示例:

# 1. 动态创建对象

public class MyFactoryBean implements FactoryBean<Object> {
    
    @Override
    public Object getObject() throws Exception {
        // 根据配置或条件动态创建对象
        if (someCondition) {
            return new MyObject();
        } else {
            return new AnotherObject();
        }
    }

    @Override
    public Class<?> getObjectType() {
        // 返回实际创建的对象的类型
        return Object.class;
    }

    @Override
    public boolean isSingleton() {
        // 返回是否为单例对象
        return true;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 2. 对象的装配和初始化

public class MyFactoryBean implements FactoryBean<MyObject> {

    private String name;
    private int age;

    @Override
    public MyObject getObject() throws Exception {
        // 创建对象并进行装配和初始化
        MyObject myObject = new MyObject();
        myObject.setName(name);
        myObject.setAge(age);
        return myObject;
    }

    @Override
    public Class<?> getObjectType() {
        return MyObject.class;
    }

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

    // 设置属性值的方法
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
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

# 3. 对象的代理和包装

public class MyFactoryBean implements FactoryBean<MyObject> {

    private MyObject target;

    @Override
    public MyObject getObject() throws Exception {
        // 对目标对象进行代理和包装
        MyObjectProxy proxy = new MyObjectProxy(target);
        return proxy.getProxy();
    }

    @Override
    public Class<?> getObjectType() {
        return MyObject.class;
    }

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

    // 设置目标对象的方法
    public void setTarget(MyObject target) {
        this.target = target;
    }
}
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

# 4. 对象的缓存和复用

public class MyFactoryBean implements FactoryBean<MyObject> {

    private static final Map<String, MyObject> objectCache = new ConcurrentHashMap<>();

    private String key;

    @Override
    public MyObject getObject() throws Exception {
        // 根据 key 从缓存中获取对象,如果不存在则创建并放入缓存
        MyObject myObject = objectCache.get(key);
        if (myObject == null) {
            myObject = new MyObject();
            objectCache.put(key, myObject);
        }
        return myObject;
    }

    @Override
    public Class<?> getObjectType() {
        return MyObject.class;
    }

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

    // 设置 key 值的方法
    public void setKey(String key) {
        this.key = key;
    }
}
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

# 5. 对象的延迟初始化

public class MyFactoryBean implements FactoryBean<MyObject>, InitializingBean {

    private MyObject myObject;

    @Override
    public MyObject getObject() throws Exception {
        return myObject;
    }

    @Override
    public Class<?> getObjectType() {
        return MyObject.class;
    }

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

    // 在初始化时创建对象
    @Override
    public void afterPropertiesSet() throws Exception {
        myObject = new MyObject();
        // 执行初始化操作
        myObject.init();
    }
}
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

# 6. 对象的销毁和资源释放

public class MyFactoryBean implements FactoryBean<MyObject>, DisposableBean {

    private MyObject myObject;

    @Override
    public MyObject getObject() throws Exception {
        return myObject;
    }

    @Override
    public Class<?> getObjectType() {
        return MyObject.class;
    }

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

    // 在销毁时释放资源
    @Override
    public void destroy() throws Exception {
        // 执行销毁操作
        myObject.release();
    }
}
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

# 2. BeanFactory

BeanFactory接口定义了IOC容器最基本的形式,并且提供了IOC容器所应该遵守的最基本的服务契约。

BeanFactory接口设计了getBean方法,这个方法是使用IOC容器API的主要方法,通过这个方法,可以取得IOC容器中管理的Bean,Bean的取得是通过指定名字来索引的。如果需要在获取Bean时对Bean的类型进行检查,BeanFactory接口定义了带有参数的getBean方法,这个方法的使用与不带参数的getBean方法类似,不同的是增加了对Bean检索的类型的要求。

在Spring中,实际上是把DefaultListableBeanFactory作为一个默认的功能完整的IOC容器来使用的。

# 有了BeanFactory的定义,用户可以执行以下操作:

  • 通过接口方法containsBean让用户能够判断容器是否含有指定名字的Bean;
  • 通过接口方法isSingleton来查询指定名字的Bean是否是Singleton类型的Bean。对于Singleton属性,用户可以在BeanDefinition中指定;
  • 通过接口方法isPrototype来查询指定名字的Bean是否是prototype类型的。与Singleton属性一样,这个属性也可以由用户在BeanDefinition中指定;
  • 通过接口方法isTypeMatch来查询指定了名字的Bean的Class类型是否是特定的Class类型。这个Class类型可以由用户来指定。
  • 通过接口方法getType来查询指定名字的Bean的Class类型;
  • 通过接口方法getAliases来查询指定了名字的Bean的所有别名,这些别名都是用户在BeanDefinition中定义的。

# BeanFactory接口源码

public interface BeanFactory {

    //对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
    //如果需要得到工厂本身,需要转义
    String FACTORY_BEAN_PREFIX = "&";
    
    //根据bean的名字,获取在IOC容器中得到bean实例
    Object getBean(String var1) throws BeansException;
    
    //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    //提供对bean的检索,看看是否在IOC容器有这个名字的bean
    boolean containsBean(String var1);

    //根据bean名字得到bean实例,并同时判断这个bean是不是单例
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    //得到bean实例的Class类型
    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    //得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
    String[] getAliases(String var1);
}
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

可以看到,这里定义的只是一系列的接口方法,通过这一系列的BeanFactory接口,可以使用不同的Bean的检索方法,很方便地从IOC容器中得到需要的Bean,从而忽略具体的IOC容器的实现。

image-20240403051019642 其中BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。

但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如

  • ListableBeanFactory 接口表示这些 Bean 是可列表的,
  • 而 HierarchicalBeanFactory 表示的是这些Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。
  • AutowireCapableBeanFactory 接口定义Bean 的自动装配规则。

这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。

在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。

而要知道工厂是如何产生对象的,我们需要看具体的IOC容器实现,spring提供了许多IOC容器的实现。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是针对最基本的ioc容器的实现,这个IOC容器可以读取XML文件定义的BeanDefinition(XML文件中对bean的描述)。

编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08
Spring6 - IOC(基于注解)
Spring6 - Bean的作用域

← Spring6 - IOC(基于注解) Spring6 - Bean的作用域→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式