Spring 中 Bean 的作用域与生命周期

3552 篇文章 114 订阅

1. Bean 的作用域

1.1 什么是 Bean 的作用域?

  Bean 的作用域是指 BeanSpring 整个框架中的某种行为模式,Bean的作用域用于定义 在IoC容器中创建的Bean实例的生命周期范围。

  案例:我们创建如下的类

User: @Getter@Setter@ToStringLombok 插件以及依赖提供,我们就不用写getsettoSpring方法了(怎么配置,后文介绍)。

@Getter @Setter @ToString public class User { private int id; private String name; }

UserBeans:

@Component public class UserBeans { //创建一个Bean,并把它放入Spring容器中。 @Bean public User user(){ User user = new User(); user.setId(1); user.setName("小明"); return user; } }

UserController:

@Controller public class UserController { @Autowired private User user;//注入User,此时 User 是“小明” public void print(){ System.out.println("user--> " + user); //修改 myUser User myUser = user; myUser.setName("张三"); System.out.println("myUser--> " + myUser); System.out.println("user--> " + user); } }

UserController2:

@Controller public class UserController2 { @Autowired private User user;//注入 public void print(){ System.out.println("user--> "+user);//目的:想得到“小明” } }

Main:

public class Main { public static void main(String[] args) { //获取Spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); UserController userController = context.getBean("userController",UserController.class); userController.print(); System.out.println("------------------------------------------------------------------------"); UserController2 userController2 = context.getBean("userController2", UserController2.class); userController2.print(); } }

结果:

  可以看到,User在全局下是同一个对象,换言之,此处的BeanSpring容器中只有一份。在任何一个地方修改此处的Bean,它的值就会改变;但是我们预期的结果是,公共 Bean 可以在各自的类中被修改,但不能影响到其他类,显然上面的代码违背了我们的预期,这就是作用域的体现。

1.1.1 Lombok 的配置

  第一步:将下面的代码赋值到pom.xml文件中

<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.26</version> <scope>provided</scope> </dependency>

  第二步:在插件商店中下载“Lombok”

  第三步:加注解

注解名称作用
@Getter自动生成 getter 方法
@Setter自动生成 setter 方法
@ToString自动生成 toString() 方法
@EqualsAndHashCode自动生成 equals()hashCode() 方法
@NoArgsConstructor自动生成无参构造函数
@AllArgsConstructor自动生成包含所有参数的构造函数
@RequiredArgsConstructor自动生成包含必需参数的构造函数
@Data自动生成 toString()equals()hashCode()gettersetter 方法

1.2 Bean 的 6 种作用域

  1. Singleton:单例作用域(默认),整个应用中只有一个 Bean 实例,每次请求时都返回同一个实例。

  2. Prototype:原型作用域,每次请求时都会创建一个新的 Bean 实例,即每次使用该 Bean 时,Spring 都会创建一个新的实例。

  3. Request:请求作用域,每次 HTTP 请求都会创建一个新的 Bean 实例,该作用域仅适用于 WebApplicationContext 环境。

  4. Session:会话作用域,每个 HTTP Session 都会创建一个新的 Bean 实例,该作用域仅适用于 WebApplicationContext 环境。

  5. Application:应用作用域,整个应用程序中只有一个 Bean 实例,该作用域仅适用于 ServletContext 环境。

  6. WebSocket:WebSocket 作用域,每个 WebSocket 连接都会创建一个新的 Bean 实例,该作用域仅适用于 WebApplicationContext 环境。

  需要注意的是,RequestSessionWebSocket 这三种作用域只适用于 WebApplicationContext(Spring MVC) 环境,即只能在 Web 应用程序中使用。而 SingletonPrototype``` 和 ``Application 三种作用域适用于所有环境。

(后 4 种状态是 Spring MVC 中的值,在普通的 Spring 项⽬中只有前两种)

1.3 自定义作用域

  还是用上面的案例,自定义作用域要用到@Scope注释,我们要在 Bean 存入容器的位置设置:

@Component public class UserBeans { //@Scope("prototye") 也可以这么写。 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)//设置为 Prototype 模式 @Bean public User user(){ User user = new User(); user.setId(1); user.setName("小明"); return user; } }

结果:

现在已经成功了。

2. Bean 的生命周期

2.1 Spring 的执行流程

  这里仅了解大概的流程:

启动 Spring 容器 -> 实例化 Bean -> Bean 注册到 Spring 中 -> 将 Bean 装配到需要的类中(注入)。

2.2 Bean 的生命周期

  在Spring框架中,一个Bean的生命周期可以分为以下几个阶段:

  1. 实例化 Bean:当Spring容器加载配置文件并初始化时,它会根据Bean定义创建Bean的实例。
  2. 属性赋值:容器会将Bean的属性注入到相应的属性中,这些属性可能是基本类型、集合或其他Bean。
  3. Bean 初始化
    • 各种通知:实现了各种 Aware 通知的⽅法,如 BeanNameAware、BeanFactoryAware、 ApplicationContextAware 的接口⽅法;
    • 执行初始化前置方法;
    • 执行初始化方法;
      • 注解方式:@PostConstruct
      • xml方式:init-method 方法
    • 执行初始化后置方法;
  4. 使用 Bean
  5. 销毁 Bean:如果 Bean 实现了 DisposableBean 接口,容器将调用它的 destroy() 方法;或者 Bean 可以定义一个自定义销毁方法(xml方式),使用 destroy-method 属性指定该方法;或者用 @PreDestroy 注释的方法。

  前置方法和后置方法通常是指实现了 BeanPostProcessor 接口的类中的方法。具体来说,BeanPostProcessor接口定义了两个方法postProcessBeforeInitialization()postProcessAfterInitialization()。前者在Bean初始化之前调用,后者在Bean初始化之后调用。

2.3 通过案例来看生命周期

  我们创建如下的类。

spring-config.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:content="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 加上这一行,因为要用到注释 --> <content:component-scan base-package="com.spring.demo.component"></content:component-scan> <!-- 这里用了 init-method="init" 来指定初始化方法 --> <bean id="beanComponent" class="com.spring.demo.component.BeanComponent" init-method="init"></bean> </beans>

BeanComponent

public class BeanComponent implements BeanNameAware { //通知方法 @Override public void setBeanName(String s) { System.out.println("执行了通知 BeanName: " + s); } //初始化方法(用xml的方式) public void init(){ System.out.println("用xml的方式->初始化方法"); } //用注释的方式初始化方法 @PostConstruct public void doPostConstruct(){ System.out.println("用注释的方式->初始化方法"); } public void hi(){ System.out.println("执行了hi()->Hello!"); } //销毁 用注释的方式 @PreDestroy public void doPreDestroy(){ System.out.println("销毁:doPreDestroy"); } }

Main

public class Main { public static void main(String[] args) { //为什么是 ClassPathXmlApplicationContext? 因为它提供了destroy方法。 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); BeanComponent beanComponent = context.getBean("beanComponent",BeanComponent.class); //调用hi方法 beanComponent.hi(); //销毁 Bean 对象 context.destroy(); } }

结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值