Bean是什么

Bean是什么

bean是什么?

1.bean定义

本质上指任何被Sping加载出来的对象。Spring Bean代表Spring最小的执行单位,其加载、作用域、生命周期的管理都由Spring操作

2.设计目的

当我们需要用容器内的对象时,只需要“告诉” Spring,Spring 就能自动帮我们加载,我们则无需考虑这个 Bean 到底是如何加载的、什么时候回收等细节逻辑。我们只需要使用即可。由此一来,降低了使用门槛,也减少了对于细节的一些管理。

3.名词介绍

定义:Bean 是在 Spring 容器中被实例化、管理和维护的对象。一个 Bean 可以是任何普通的 Java 对象,例如 POJO、Service、Respository、Controller 等等。将一个类声明为 Bean 的方式可以是在类级别上使用 ‘@Component’ 注解或其派生注解(‘@Service’、‘@Repository’、‘@Controller’等),也可以是通过配置文件进行显式的声明。

实例化:Spring 容器负责实例化 Bean。当应用程序启动时,Spring 容器会根据配置信息或注解扫描的结果,找到并实例化所有被标记为 Bean 的类,并将它们加入容器中。实例化的过程由 Spring 的 IoC 容器负责。

管理:一旦 Bean 被实例化,Spring 容器将负责管理 Bean 的生命周期和依赖关系。它会根据配置文件或注解的信息,自动解决 Bean 之间的依赖关系,确保在需要的时候正确的注入依赖。Spring 容器还会负责销毁不再需要的 Bean。

依赖注入:依赖注入是 Spring 框架的一个重要特性,它允许通过自动或显式配置的方式将 Bean 的依赖项注入到其它 Bean 中。依赖注入可以通过构造函数注入、Setter 方法注入或字段注入的方式实现,其中最常见的是使用 ‘@Autowired’注解进行注入。

作用域:Spring 框架提供了多种作用域(scope)来管理 Bean 的生命周期。常见的作用域包括单例(Singleton)、原型(Prototype)、会话(Session)、请求(Request)等。默认情况下,Bean 是单例的,即每个容器中只存在一个实例。但可以根据需要配置其它作用域。

点击查看代码

@Component // 默认为单例

public class MyBean {

// 代码...

}

-------------------------------------

@Component

@Scope("prototype")

public class MyPrototypeBean {

// 代码...

}

6. 自动装配:Spring Boot 支持自动装配(Auto - wiring),它能够根据类型或名称自动解析和注入依赖关系。通过在需要注入的字段、构造函数或 Setter 方法上使用 ‘@Autowired’ 注解,Spring 容器会自动查找并注入对应的 Bean。

点击查看代码

@Component

public class MyService {

@Autowired

private MyBean myBean;

// 使用myBean的代码...

}

4.装配及注入

了解Spring设计Bean的目的后,我们了解如何告诉Spring我们需要一个Bean。下面以MyBean为例,我们一步一步介绍如何管理、加载Bean

点击查看代码

@Data

// 这是Lombok提供的组合注解,自动为类生成getter 和 setter 方法、toString方法、equals和hashCode方法

@AllArgsConstructor

// 生成一个包含所有字段的构造函数。

@NoArgsConstructor

// 生成一个无参构造函数

public class MyBean {

Integer filedA;

Integer fieldB;

}

Spring 对于 Bean 的装配有三种方式:xml 装配、Java 显式配置和自动装配。

xml 装配

xml装配就不介绍了,因为是比较老的装配方式了

Java 装配

经常在第三方项目中,如果我们想要注入一个容器,那么往往需要通过注解 @Configuration + @Bean 的方式进行实现。如下所示:

点击查看代码

@Configuration

public class MyBeanConfiguration {

@Bean(name = "myBean")

public MyBean initMyBean() {

return new MyBean();

}

}

-------------------------------------------------

@SpringBootApplication

@ComponentScan(basePackages = {"com.example.demo.*", "com.alibaba"}) // 需指明路径。

public class emptyDemoApplication {

public static void main(String[] args) {

ConfigurableApplicationContext context = SpringApplication.run(emptyDemoApplication.class, args);

Object myBean = context.getBean("myBean");

System.out.println(myBean); // MyBean(filedA=null, fieldB=null)

}

}

需要注意的点是,Spring 默认是不会开启第三方的 bean 扫描的(这个取决于下面一种的自动装配机制。),如果需要对第三方的包进行扫描,那么需要采用 @ComponentScan 注解进行显式的指明。

自动装配

自动装配机制是 SpringBoot 的一大亮点之一,其主要依赖于 @SpringBootApplication 下的 @EnableAutoConfiguration 注解(该注解在 @SpringBootApplication 注解里面,看源码可以看到)实现。简单来说,就是在该注解指定的目录下,通过使用 @Component 及其衍生注解如 @Service、@Repository 等,Spring 就会默认将对应对象注册到容器中。具体例子如下:

点击查看代码

@Data

@AllArgsConstructor

@NoArgsConstructor

@Component

public class MyBean {

Integer filedA;

Integer fieldB;

}

-------------------------------------------------

@SpringBootApplication

@ComponentScan(basePackages = {"com.example.demo.*", "com.alibaba"}) // 需指明路径。

public class emptyDemoApplication {

public static void main(String[] args) {

ConfigurableApplicationContext context = SpringApplication.run(emptyDemoApplication.class, args);

Object myBean = context.getBean("myBean");

System.out.println(myBean); // MyBean(filedA=null, fieldB=null)

}

}

自动装配的方案,遵循了“约定大于配置”的设计理念,通过约定俗成来极大减少了程序员开发的成本。在通常情况下,Spring 只会默认扫描当前类路径下的组件,不会扫描其它第三方包组件。可以通过上文的 @ComponentScan 来扩充扫描的范围。

五、生命周期

5.1 作用域

在了解了 Bean 的设计目的及其装配注入的方式后,咋们有必要对 Bean 的整个生命周期做一个了解。但是在了解具体的生命周期之前,我们需要了解一个概念,即容器的作用域。作用域大致有以下五种:

singleton(默认):将单个 bean 定义限定为每个 Spring IoC 容器的单个对象实例。

prototype:将单个 bean 定义限定为任意数量的对象实例

request:每次用户请求时,只生成一个 Bean 对象

session:每次 Http 会话建立到终止时,只能够生成一个对应的 Bean 实例

application: 每次应用启动到终止,只维持一个对应的 Bean 实例对象

从含义的解释上来看,作用域主要是解决 Bean 的作用范围的。以 singleton 和 prototype 来说,singleton 在创建之后,springboot 会保证整个上下文环境中都只存在一个该类型的 bean。而如果是 prototype 情况,那么每次 springboot 发生加载的时候,都会新创建一个 bean 进行注入。

相似的,request、session则是在每次用户请求、每次会话建立都新创建 bean 进行注入。通过指定作用域,我们就可以判断出当前这个 Bean 对象的大致生命周期和作用范围。

5.2 生命周期

从主观上来考虑,一个 Bean 在容器中管理,大概需要以下这么几步:

调用构造方法,创建对应的 Bean 类。此时 Bean 类中的属性都是空的。

将 Bean 所依赖的一些数据,如待注入的容器等,填充到 Bean 对象中。

调用 bean 内的一些方法,如启动数据库链接等。同时将 Bean 填充到容器中存储起来,以方便应用程序获取使用。

如果当前不再使用该 Bean 对象,则调用销毁方法,将当前 Bean 销毁。

而这上述几步,其实也就对应着 Bean 生命周期:

实例化 Instantiation(指创建对象的过程,也就是说,当 Spring 容器启动时,它会扫描所有的配置文件,读取 Bean 定义,然后根据定义创建 Bean 对象的实例。这个过程中,Spring 容器会使用反射机制来调用 Bean 的构造函数来实例化对象。)

属性赋值 Populate

初始化 Initialization(指 Bean 对象被创建后,Spring 容器会根据配置文件中的定义来对其进行一系列的属性设置、依赖注入等操作,使其可以正常运行。这个过程中,Spring 容器会调用 Bean 的一些特定方法,如 set 方法、init-method 方法等来完成对象的初始化。)

销毁 Destruction

实例化和初始化的区别:实例化是创建对象的过程,而初始化是为对象设置属性、注入依赖以及调用特定方法来使其准备好执行操作的过程。在 Spring 框架中,实例化和初始化都是由容器来管理的,可以通过配置文件或者注解来指定 Bean 的创建和初始化过程。

同时,为了方便拓展,Spring 也在特定的生命周期前后提供了接口以供拓展实现,最重要的两个实现接口就是如下两个:

InstantiationAwareBeanPostProcessor

BeanPostProcessor

InstantiationAwareBeanPostProcessor 主要在 Bean 实例化、属性赋值的时候提供了拓展接口;

而 BeanPostProcessor 则主要在 Bean 初始化前后提供拓展接口。我们熟知的 @PostConstruct 注解,就是通过实现了 BeanPostProcessor 接口,来实现的后处理机制。

总体来说,Spring 中 bean 的基本生命流程主要如下所示:

生命周期

从主观上来考虑,一个 Bean 在容器中管理,大概需要以下这么几步:

调用构造方法,创建对应的 Bean 类。此时 Bean 类中的属性都是空的。

将 Bean 所依赖的一些数据,如待注入的容器等,填充到 Bean 对象中。

调用 bean 内的一些方法,如启动数据库链接等。同时将 Bean 填充到容器中存储起来,以方便应用程序获取使用。

如果当前不再使用该 Bean 对象,则调用销毁方法,将当前 Bean 销毁。

而这上述几步,其实也就对应着 Bean 生命周期:

实例化 Instantiation(指创建对象的过程,也就是说,当 Spring 容器启动时,它会扫描所有的配置文件,读取 Bean 定义,然后根据定义创建 Bean 对象的实例。这个过程中,Spring 容器会使用反射机制来调用 Bean 的构造函数来实例化对象。)

属性赋值 Populate

初始化 Initialization(指 Bean 对象被创建后,Spring 容器会根据配置文件中的定义来对其进行一系列的属性设置、依赖注入等操作,使其可以正常运行。这个过程中,Spring 容器会调用 Bean 的一些特定方法,如 set 方法、init-method 方法等来完成对象的初始化。)

销毁 Destruction

实例化和初始化的区别:实例化是创建对象的过程,而初始化是为对象设置属性、注入依赖以及调用特定方法来使其准备好执行操作的过程。在 Spring 框架中,实例化和初始化都是由容器来管理的,可以通过配置文件或者注解来指定 Bean 的创建和初始化过程。

同时,为了方便拓展,Spring 也在特定的生命周期前后提供了接口以供拓展实现,最重要的两个实现接口就是如下两个:

InstantiationAwareBeanPostProcessor

BeanPostProcessor

InstantiationAwareBeanPostProcessor 主要在 Bean 实例化、属性赋值的时候提供了拓展接口;

而 BeanPostProcessor 则主要在 Bean 初始化前后提供拓展接口。我们熟知的 @PostConstruct 注解,就是通过实现了 BeanPostProcessor 接口,来实现的后处理机制。

总体来说,Spring 中 bean 的基本生命流程主要如下所示:

这张图展示了 Spring 框架中 Bean 的生命周期及其与 BeanPostProcessor 和 InstantiationAwareBeanPostProcessor 接口的交互过程。Spring 容器管理 Bean 的整个生命周期,从定义到销毁,而这些接口允许开发者在特定阶段对 Bean 进行自定义处理。

Bean Definition

起点:一切开始于一个 Bean 的定义(Bean Definition),它描述了如何创建和配置一个 Bean。

实例化(createBeanInstance)

postProcessBeforeInstantiation:

在 Bean 实例化之前,Spring 会调用所有实现了 InstantiationAwareBeanPostProcessor 接口的处理器的 postProcessBeforeInstantiation 方法。

如果某个处理器返回了一个非空对象,那么这个对象将被用作最终的 Bean 实例,跳过后续的实例化步骤。

实例化 createBeanInstance:

如果没有处理器返回非空对象,则 Spring 将根据 Bean 定义创建一个新的 Bean 实例。

属性赋值(populateBean)

postProcessAfterInstantiation:

在 Bean 实例化之后、属性赋值之前,Spring 会再次调用 InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation 方法。

如果该方法返回 false,则跳过属性赋值步骤。

属性赋值 populateBean:

如果 postProcessAfterInstantiation 返回 true 或未实现,Spring 将根据 Bean 定义设置 Bean 的属性值。

postProcessProperties:

属性赋值完成后,Spring 调用 BeanPostProcessor 的 postProcessProperties 方法(如果实现的话)。

postProcessPropertyValues:

最后,Spring 调用 InstantiationAwareBeanPostProcessor 的 postProcessPropertyValues 方法,允许进一步修改属性值。

初始化(initializeBean)

postProcessBeforeInitialization:

在 Bean 初始化之前,Spring 调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法。

初始化 initializeBean:

Bean 初始化包括调用初始化方法(如 @PostConstruct 注解的方法或通过 元素的 init-method 属性指定的方法)。

afterPropertiesSet():

如果 Bean 实现了 InitializingBean 接口,Spring 会调用其 afterPropertiesSet() 方法。

postProcessAfterInitialization:

在 Bean 初始化完成之后,Spring 调用 BeanPostProcessor 的 postProcessAfterInitialization 方法。

使用 ing……

Bean 准备就绪,可以被应用程序使用。

销毁(destroyBean)

当 Bean 不再需要时,Spring 调用销毁方法(如 @PreDestroy 注解的方法或通过 元素的 destroy-method 属性指定的方法)来清理资源。

总结

BeanPostProcessor 和 InstantiationAwareBeanPostProcessor 是两个重要的接口,允许开发者在 Bean 生命周期的不同阶段进行干预和自定义处理。

图中的箭头表示流程的方向,绿色方框代表可以在对应阶段进行干预的接口方法。

通过理解这些流程和接口,开发者可以更灵活地控制和扩展 Spring 容器中 Bean 的行为。

参考文章:https://blog.csdn.net/yuxiangdeming/article/details/135648586

相关推荐

為甚麼人死了會瞳孔放大
365bet怎么提款

為甚麼人死了會瞳孔放大

📅 07-15 👁️ 8733
《哔哩哔哩》以下乱码语哪个代表曹操
365bet怎么提款

《哔哩哔哩》以下乱码语哪个代表曹操

📅 09-25 👁️ 2466
涉嫌非法集资罪怎么判
365bet怎么提款

涉嫌非法集资罪怎么判

📅 09-04 👁️ 1215