Bean对象的运行和原理详解

Bean运行详解

在 Spring 框架中,实例化一个 Bean 的详细流程如下:

  1. 根据配置文件或注解等方式,Spring IoC 容器创建 BeanDefinition 对象,该对象包含了 Bean 的所有信息,例如类名、构造函数、属性、依赖关系等。
  2. 当容器启动时,根据 BeanDefinition 对象创建 Bean 实例。如果该 Bean 是单例的,容器会在启动时创建该实例并保存到单例缓存中。如果是原型的,容器将在每次请求时创建一个新的实例。
  3. 容器根据 BeanDefinition 中的信息,调用构造函数创建 Bean 实例。
  4. 容器为 Bean 实例注入属性值和依赖关系。这个过程中,容器会根据 BeanDefinition 中的信息,从容器中获取相应的依赖对象,并将它们注入到 Bean 实例中。
  5. 如果 Bean 实现了 InitializingBean 接口,容器将调用其 afterPropertiesSet() 方法,执行 Bean 的初始化操作。
  6. 如果 Bean 使用了 @PostConstruct 注解,容器将调用标注了该注解的方法,执行 Bean 的初始化操作。
  7. Bean 实例化完成后,容器将把它保存到 BeanFactory 中,以供后续使用。

总的来说,实例化一个 Bean 的过程是比较复杂的,需要从配置、依赖注入、初始化等多个方面进行考虑和处理。但是 Spring IoC 容器可以根据 BeanDefinition 对象来自动完成这些过程,让开发者只需要关注 Bean 的定义和功能实现即可。

BeanDefinition 对象详细解释

在 Spring 中,BeanDefinition 对象是用来描述 Bean 的元数据的。它包含了 Bean 的类名、构造函数、属性、依赖关系、作用域等信息。在 Spring IoC 容器中,BeanDefinition 对象是在 Bean 的定义阶段被创建的,它描述了容器如何创建 Bean 实例,并在实例化过程中如何对其进行初始化和依赖注入。

一个 BeanDefinition 对象包含以下信息:

  1. 类名:指定 Bean 的类名。
  2. 是否抽象:标识该 Bean 是否为抽象 Bean,抽象 Bean 是不能被实例化的。
  3. 是否懒加载:指定该 Bean 是否为懒加载,即是否在第一次使用时才进行实例化。
  4. 是否单例:指定该 Bean 是否为单例 Bean,即在容器中只存在一个实例。
  5. 作用域:指定该 Bean 的作用域,可以是 singleton、prototype、request、session、application 等。
  6. 构造函数:指定 Bean 的构造函数,包括参数类型和参数值。
  7. 属性:指定 Bean 的属性,包括属性名和属性值。
  8. 依赖关系:指定 Bean 依赖的其他 Bean。

通过 BeanDefinition 对象,Spring 容器可以了解 Bean 的元数据信息,并在需要时对 Bean 进行创建、初始化和销毁等操作。BeanDefinition 对象是 Spring IoC 容器的核心组件之一,它体现了 Spring 框架的灵活性和可扩展性,使得开发者可以通过配置文件或注解等方式来定义 Bean,而不需要直接操作 Bean 实例。

如果 Bean 实现了 InitializingBean 接口有什么用

如果 Bean 实现了 InitializingBean 接口,其 afterPropertiesSet() 方法将会在 Bean 的属性注入完成后、在 Bean 初始化方法执行之前被 Spring 容器调用。这样可以保证 Bean 在属性注入完成后立即执行初始化操作,确保 Bean 的属性已经被正确地注入。

使用 InitializingBean 接口可以将 Bean 的初始化逻辑与 Spring 容器解耦,使得 Bean 可以被多个容器重用。同时,使用 InitializingBean 接口也可以保证初始化逻辑的顺序,因为在容器中,Bean 的初始化顺序可能会影响到其他 Bean 的初始化。

需要注意的是,使用 InitializingBean 接口会使 Bean 和 Spring 框架产生强耦合,不太适合在非 Spring 环境下使用。另外,如果 Bean 中有大量的初始化逻辑,使用 InitializingBean 接口可能会使 Bean 过于臃肿,影响代码的可读性和维护性。因此,在实际开发中,可以使用 @PostConstruct 注解或自定义的初始化方法等方式来代替 InitializingBean 接口。

从IOC容器里面取得一个Bean的流程

从 IoC 容器中获取一个 Bean 的详细流程如下:

  1. 加载 Spring 配置文件:首先需要加载 Spring 配置文件,这可以通过使用 ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext 等容器实现。
  2. 创建 BeanFactory:容器在加载配置文件时,会解析配置文件中的 Bean 定义,并将其存储在内部的 BeanFactory 中。
  3. 定位 Bean 定义:当调用容器的 getBean() 方法获取 Bean 实例时,容器会根据 Bean 的 ID 或名称定位 Bean 定义。
  4. 创建 Bean 实例:当容器找到了 Bean 的定义后,就会根据定义创建 Bean 实例。在创建 Bean 实例之前,容器需要先判断该 Bean 是否为单例 Bean,如果是,则容器会检查该 Bean 是否已经创建过,如果已经创建过,则直接返回现有的 Bean 实例,否则会创建一个新的 Bean 实例。如果该 Bean 是多例 Bean,则容器会每次调用 getBean() 方法时都创建一个新的 Bean 实例。
  5. Bean 属性赋值:在 Bean 实例化之后,容器会对 Bean 的属性进行赋值,这些属性值通常来自配置文件中的  标签或 @Autowired 注解。
  6. Aware 回调:如果该 Bean 实现了 Aware 接口,则容器会自动调用该接口的回调方法,以便 Bean 获取容器相关的信息。
  7. BeanPostProcessor 处理:如果该 Bean 实现了 BeanPostProcessor 接口,则容器会在 Bean 初始化前后调用 BeanPostProcessor 的 postProcessBeforeInitialization() 和 postProcessAfterInitialization() 方法。
  8. 初始化 Bean:在 Bean 属性赋值和 Aware 回调之后,容器会调用 Bean 的初始化方法,包括实现了 InitializingBean 接口的 afterPropertiesSet() 方法和使用 @PostConstruct 注解标记的方法。
  9. 返回 Bean 实例:当 Bean 初始化完成后,容器会将其返回给调用者,调用者可以通过 Bean 实例来访问 Bean 的方法和属性。
  10. 销毁 Bean:当容器关闭时,会调用实现了 DisposableBean 接口的 destroy() 方法和使用 @PreDestroy 注解标记的方法,以销毁 Bean 实例并释放资源。

以上是从 Spring IoC 容器中获取 Bean 的详细流程,需要注意的是,如果 Bean 的作用域为 prototype,那么每次调用 getBean() 方法都会创建一个新的 Bean 实例,而如果 Bean 的作用域为 singleton,那么容器中只会存在一个 Bean 实例。同时,在获取 Bean 时,如果 Bean 的依赖关系出现循环依赖,会抛出 BeanCurrentlyInCreationException 异常。

BeanWrapper

在 Spring IoC 容器中,BeanWrapper 是用来包装 Bean 实例的对象,它是一个抽象出来的 Bean 实例的代理对象,提供了一系列访问和操作 Bean 实例的方法。在 Spring IoC 容器中,BeanWrapper 负责对 Bean 实例进行依赖注入、属性赋值和事件监听等操作,同时还提供了对 Bean 属性值的获取和设置、类型转换等功能。

BeanWrapper 中最常用的方法包括:

  1. getPropertyValues():获取 Bean 实例的属性值集合。
  2. setPropertyValues():为 Bean 实例设置属性值。
  3. getPropertyValue():获取 Bean 实例的指定属性值。
  4. setPropertyValue():为 Bean 实例设置指定属性值。
  5. getWrappedInstance():获取包装的 Bean 实例对象。
  6. getWrappedClass():获取包装的 Bean 实例对象的 Class 对象。
  7. setAutoGrowNestedPaths():设置是否支持自动扩展嵌套路径,如果启用自动扩展,则在访问属性路径时,将自动创建中间的 Bean 对象。

BeanWrapper 的实现类是 org.springframework.beans.BeanWrapperImpl,它是一个默认的 BeanWrapper 实现,使用 SimpleTypeConverter 进行类型转换。BeanWrapperImpl 实现了 BeanWrapper 接口,同时也继承了 PropertyAccessor 接口和 ConfigurablePropertyAccessor 接口,提供了一些额外的访问 Bean 属性的方法。

总之,BeanWrapper 提供了一种灵活的访问和操作 Bean 实例的方式,可以通过 BeanWrapper 对象来获取和设置 Bean 实例的属性值,从而实现对 Bean 实例的控制。

BeanFactoryBuilder

BeanFactoryBuilder 是一个用于创建 Spring IoC 容器的工厂构建器。在 Spring 中,BeanFactory 是一个负责管理和创建 Bean 对象的接口,Spring 容器的核心就是 BeanFactory 接口的实现类,用于提供 Bean 的实例化、初始化、依赖注入等功能。BeanFactoryBuilder 可以帮助我们创建 BeanFactory 的实现类。

BeanFactoryBuilder 可以用于创建多种类型的 Spring 容器,包括 ApplicationContext、WebApplicationContext、XmlWebApplicationContext 等,可以根据不同的场景和需求创建不同的容器。BeanFactoryBuilder 支持从多种不同的资源类型中加载配置信息,例如 properties 文件、XML 文件、Java 配置类等。

BeanFactoryBuilder 的主要作用是解析容器配置信息,并使用这些配置信息创建 BeanFactory 对象。在创建 BeanFactory 对象时,BeanFactoryBuilder 还会为容器设置 BeanPostProcessor、PropertyEditorRegistrar 等组件,以及一些监听器等。通过 BeanFactoryBuilder 创建的 BeanFactory 对象可以被用来获取 Bean 实例,并提供诸如依赖注入、Bean 生命周期管理等核心功能。

在 Spring 5.0 及以后版本中,BeanFactoryBuilder 已经被废弃,推荐使用更加简单和灵活的方式来创建 Spring 容器,例如使用注解配置和 Java 配置类等。

InitializingBean

InitializingBean 是一个 Spring 框架提供的接口,用于在 Bean 实例化完成后进行初始化操作。当 Spring 容器完成 Bean 的实例化、依赖注入等操作后,如果 Bean 实现了 InitializingBean 接口,容器会自动调用它的 afterPropertiesSet() 方法,以便在 Bean 实例化完成后执行初始化逻辑。

InitializingBean 接口中只有一个方法:afterPropertiesSet()。通过实现 InitializingBean 接口并重写 afterPropertiesSet() 方法,可以在 Bean 实例化完成后执行一些初始化逻辑。例如,可以在该方法中进行一些数据的初始化、资源的加载、服务的注册等操作。在 afterPropertiesSet() 方法中,还可以使用 Spring 容器中的其他 Bean 对象,以便在初始化逻辑中进行依赖注入。

与 InitializingBean 对应的是 DisposableBean 接口,它定义了一个 destroy() 方法,用于在 Bean 销毁之前执行一些清理操作。当 Bean 实现了 DisposableBean 接口时,Spring 容器会自动调用它的 destroy() 方法,在销毁 Bean 之前执行清理逻辑。

需要注意的是,使用 InitializingBean 和 DisposableBean 接口来定义 Bean 的初始化和销毁方法,会将 Bean 和 Spring 框架耦合在一起。为了避免这种耦合,Spring 还提供了另外两种方式来定义 Bean 的初始化和销毁方法:@PostConstruct 和 @PreDestroy 注解。

BeanPostProcessor

BeanPostProcessor 是 Spring 容器中的一个扩展点,用于在 Bean 实例化、依赖注入和初始化等过程中,对 Bean 进行后置处理。BeanPostProcessor 接口提供了两个方法:

  • postProcessBeforeInitialization(Object bean, String beanName):在 Bean 初始化前调用,可以对 Bean 进行一些自定义处理。
  • postProcessAfterInitialization(Object bean, String beanName):在 Bean 初始化后调用,可以对 Bean 进行一些自定义处理。

在 Spring 容器中,BeanPostProcessor 的作用非常广泛,可以用于各种场景,例如:

  • 属性填充:可以在 Bean 初始化前后,对 Bean 的属性进行一些自定义填充,例如对密码进行加密、对日期进行格式化等。
  • AOP 功能:可以在 Bean 初始化前后,对 Bean 进行一些 AOP 功能的增强,例如对 Bean 进行事务管理、对 Bean 进行性能监控等。
  • Bean 包装:可以在 Bean 初始化前后,对 Bean 进行一些包装,例如使用代理对象包装 Bean、使用装饰者模式包装 Bean 等。

当一个 Bean 实现了 BeanPostProcessor 接口后,Spring 容器会自动将该 Bean 注册为一个 BeanPostProcessor,然后在每个 Bean 实例化和初始化的过程中,自动调用它的 postProcessBeforeInitialization() 和 postProcessAfterInitialization() 方法。在这两个方法中,可以通过返回一个新的对象,来替换原有的 Bean 实例,从而对 Bean 进行替换、代理和包装等操作。

获取Bean实例

在 Spring 容器中,可以通过 ApplicationContext 或者 BeanFactory 来获取 Bean,它们都提供了多个重载方法,以便根据 Bean 的类型或名称等信息来获取指定的 Bean。

以下是获取 Bean 的示例代码:

// 获取 ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 当然想要获取对应Bean对象有可以获取一个BeanFactoryBuilder对象然后获取对应的BeanFactory
// 获取 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

// 从 ApplicationContext 中获取 Bean
MyBean myBean = context.getBean(MyBean.class);
MyBean myBean2 = (MyBean) context.getBean("myBean");

// 从 BeanFactory 中获取 Bean
MyBean myBean3 = beanFactory.getBean(MyBean.class);
MyBean myBean4 = (MyBean) beanFactory.getBean("myBean");

以上代码中,MyBean 是一个自定义的 Bean 类型,可以是任意的 Java 类。"myBean" 是该 Bean 在 Spring 容器中的名称,可以在 Bean 的定义文件中通过 idname 属性指定。

当获取 Bean 的时候,如果指定的 Bean 在 Spring 容器中不存在,那么会抛出 NoSuchBeanDefinitionException 异常。因此,在获取 Bean 之前,需要确保该 Bean 在 Spring 容器中已经注册,并且名称和类型都是正确的。

Bean的6大作用域

在 Java 中,Bean 的作用域指的是在容器中存储和管理 Bean 实例的范围,常用的作用域有以下六种:

  1. 单例作用域(Singleton Scope):单例作用域指的是容器中只存在一个 Bean 实例,这个实例会被缓存起来,每次请求都会返回同一个实例。适用于需要多次使用同一个 Bean 实例的场景。
  2. 原型作用域(Prototype Scope):原型作用域指的是容器每次请求都会创建一个新的 Bean 实例,并返回这个实例。适用于每次请求都需要使用一个新的 Bean 实例的场景。
  3. 会话作用域(Session Scope):会话作用域指的是在一个会话期间内只创建一个 Bean 实例。会话作用域的 Bean 实例在整个会话期间内都是可用的,适用于需要在整个会话期间内共享数据的场景。
  4. 请求作用域(Request Scope):请求作用域指的是在每个请求处理期间创建一个 Bean 实例,请求作用域的 Bean 实例只在请求处理期间内可用。适用于需要在一个请求处理期间内共享数据的场景。
  5. 全局会话作用域(Global Session Scope):全局会话作用域指的是在整个 Web 应用程序中只有一个 Bean 实例,这个实例与每个用户的会话相关联。适用于需要在整个应用程序中共享数据,并且与每个用户的会话相关联的场景。
  6. 应用程序作用域(Application Scope):应用程序作用域指的是在整个 Web 应用程序中只有一个 Bean 实例。应用程序作用域的 Bean 实例在整个 Web 应用程序的生命周期中都是可用的,适用于需要在整个应用程序中共享数据的场景。

这些作用域可以让开发人员根据实际需求选择合适的作用域,以实现不同范围内数据的共享和管理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

堕落年代

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值