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
相关推荐
流烟默1 小时前
MCP第 5 篇:用 Spring AI 写 MCP:注解、自动配置、ChatClient 集成
人工智能·spring·mcp封装
来福猿3 小时前
SpringCloud Config 源码分析:配置拉取、刷新与多环境管理
后端·spring·spring cloud
雷一言说7 小时前
Spring AI 2.0 RAG:用 Metadata Filter 做多租户检索隔离
java·spring
摇滚侠7 小时前
《大模型应用开发实践:基于 Spring AI+DeepSeek 实现》第 11 章 大模型技术概览 阅读笔记 1
人工智能·笔记·spring
一枕槐安48713 小时前
大模型应用后端设计:上下文管理、缓存、降级策略的工程方案总结
java·spring·缓存
步行cgn13 小时前
@RequestMapping 注解详解
java·后端·spring
摇滚侠15 小时前
《大模型应用开发实践:基于 Spring AI+DeepSeek 实现》第 12 章 Spring AI 开发入门 阅读笔记 2
人工智能·笔记·spring
weixin_BYSJ198716 小时前
【计算机毕设】基于Spring_Boot_Vue的马拉松报名与选手成绩追踪系统05445
java·vue.js·spring boot·学习·spring·django·课程设计
小坏讲微服务1 天前
刚发布一个月的JDK 27,为什么我建议你立刻升级?
java·开发语言·spring boot·spring·架构·求职招聘·springboot4
snow@li1 天前
SpringBoot:核心注解全景梳理 / @xxx 叫“注解”(Annotation)
java·spring