Bean的作用域和生命周期

变量的作用域

变量的作用域是指一个变量生效的范围,作用的范围。比如定义了一个类变量,就意味着类里面的所有方法都可以使用;如果变量定义在方法里面,就称为方法变量,方法变量只能在方法里面去使用。

Bean的作用域

Bean是Spring里面存储的对象,Bean的作用域指的是Bean对象在Spring容器里面的行为。

下面我们用一个例子来看Bean作用域问题:

  • 我们先创建一个公共类Users,调用getUser()方法可以或得一个公共的User对象,我们设置这个公共类的User的id为222,User的name为李四:
java 复制代码
package com.java.demo.model;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
// 公共类
@Component
public class Users {
    @Bean("user")
    public  User getUser(){
         User user=new User();
         user.setId(222);
         getUser().setName("李四");
         return  user;
    }
}
  • 假设有两个人需要对这个公共类进行改进,在这里我们用UserController2和UserController3来代表这两个人。
  • UserController2对公共对象的操作如下:
java 复制代码
import com.java.demo.model.User;
import com.java.demo.model.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController2 {
    @Autowired
    private User user;
    public  void doMethod(){
        User  user2=user;
        System.out.println("UserController2修改之前"+user);
        user2.setName("张三");
        user2.setId(1111);
        System.out.println("UserController2修改之前:"+user);
    }
}

UserController2先定义了一个User类型的变量user2然后将user给user2,然后打印了一下修改之前的user,接着对user2进行id设置和name设置,最后打印一下修改后的user。
可以看到,公共对象user已经被修改了,id和name都被UserController2进行了修改。虽然UserController2是对user2进行了操作,可是还是改变了原本的user。

我们再看一下 UserController3:

java 复制代码
package com.java.demo.controller;

import com.java.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

@Controller
public class UserController3 {
    @Autowired
    private User user;
    public void doMethod(){
        System.out.println("UserController3 的user:"+user);
    }
}

UserController3并没有对公共对象user进行任和操作,只是在doMethod方法里面打印了一下公共对象user。UserController3希望拿到的user是没有被改动的user,那我们来看一下代码执行的结果(我们在main方法里面,先调用UserController2的doMethod方法,再调用UserController3的doMethod方法):
代码执行结果:

结果发现,虽然UserController2重新定义了一个变量,然后进行修改,但是原来的公共对象依旧被改动了,导致UserController3拿到的公共对象user已经是被改动后的了。

导致这样结果的原因就是:

java 复制代码
  private User user;
   User  user2=user;

这里代码实际上定义一个User类型的变量,这个变量指向的是user对象,并没有新的对象。这时候使用user2去修改对象的时候,就相当于修改了user对象。

归根结底导致这个问题的原因就是Bean的作用域,Bean对象默认的是单例模式。(单例模式是指在程序的运行期间只有一份)。

  • 如何避免默认单例模式带来的问题?
    手动设置,通过@Scope注解,如@Scope("prototype")、prototype就是原型模式:
java 复制代码
package com.java.demo.model;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
// 公共类
@Component
public class Users {
    @Bean
    @Scope("prototype")
    public  User getUser(){
         User user=new User();
         user.setId(222);
        user.setName("李四");
         return  user;
    }
}

Bean作用域类型:

概念:Bean作用域指的是Bean在Spring容器中的某种行为,比如单例模式,比如原型模式等。

  1. singleton:单例作用域(默认的作用域)
    补充问题:单例模式的Bean是线程安全的吗?不是,因为所有人都可以操作这个公共变量,所以不是线程安全的,使用ThreadLocal可以变成线程安全的。
  2. prototype:原型作用域(多例模式)
  3. request:请求作用域,只适用于Spring MVC项目(就是Spring Web项目)
  4. session:回话作用域,一个Http会话共享一个Bean,是适用于Spring MVC项目。
  5. application:全局作用域,表示的是一个Context容器共享一个作用域。只适用于Spring MVC项目。
  6. websocket:Http WebSocket作用域,只适用于Webscoket作用域。

Spring的生命周期

  1. 启动容器
  2. 读取配置文件,进行Bean的实例化
  3. 将Bean加入到容器中
  4. 装配Bean属性(给当前类的属性赋值)

Bean的生命周期

  1. 实例化(内存空间的分配)
  2. 设置Bean属性(进行依赖注入,将依赖的Bean赋值到当前类的属性上)
  3. Bean的初始化
    3.1 执行各种通知
    3.2 初始化的前置方法
    3.3 初始化方法
    3.4 初始化的后置方法
  4. 使用Bean
  5. 销毁Bean
相关推荐
麦兜*2 小时前
基于Spring Boot的审计日志自动化解决方案,结合SpEL表达式和AOP技术,实现操作轨迹自动记录,并满足GDPR合规要求
java·jvm·spring boot·后端·spring·spring cloud·maven
探索java12 小时前
深入解析 Spring 获取 XML 验证模式的过程
xml·java·spring
Java水解18 小时前
Spring AI模块化RAG架构解析:三阶段设计与实现详解
后端·spring
Mr Aokey21 小时前
告别配置混乱!Spring Boot 中 Properties 与 YAML 的深度解析与最佳实践
java·spring·rpc
杨DaB1 天前
【SpringMVC】MVC中Controller的配置 、RestFul的使用、页面重定向和转发
java·笔记·后端·学习·spring·mvc·restful
Code季风1 天前
深入 Spring IoC 容器:六大关键应用场景助力项目开发
java·spring
小七mod1 天前
【Spring】Spring Boot启动过程源码解析
java·spring boot·spring·面试·ssm·源码
是2的10次方啊1 天前
Spring全家桶深度解析:从菜鸟到大神的进阶之路
spring boot·spring·spring cloud
愿你天黑有灯下雨有伞1 天前
Spring Boot SSE实战:SseEmitter实现多客户端事件广播与心跳保活
java·spring boot·spring
KNeeg_2 天前
Spring循环依赖以及三个级别缓存
java·spring·缓存