当前位置: 首页 > news >正文

循序渐进学 Spring (上):从 IoC/DI 核心原理到 XML 配置实战

文章目录

    • 0. 写在前面
    • 1. Spring 核心概念
      • 1.1 简介
      • 1.2 优点
      • 1.3 组成 (Spring Framework Modules)
      • 1.4 拓展
    • 2. IoC 理论推导 (控制反转)
      • 2.1 从一个实例开始理解
        • 步骤一:传统开发方式(主动创建依赖)
        • 步骤二:改进方式(通过 Setter 注入)
      • 2.2 IoC 的本质
    • 3. 第一个 Spring 程序 (HelloSpring)
      • 核心概念回顾
    • 4. IoC 创建对象的方式
      • 4.1 方式一:使用无参构造函数 (默认)
      • 4.2 方式二:使用有参构造函数
    • 5. Spring 配置详解
      • 5.1 别名 (`<alias>`)
      • 5.2 Bean 的基本配置 (`id`, `class`, `name`)
      • 5.3 导入其他配置 (`<import>`)
    • 6. 依赖注入 (DI)
      • 6.1 构造器注入
      • 6.2 Set 注入 (重点)
      • 6.3 拓展方式注入 (p-命名空间和c-命名空间)
      • 6.4 Bean 的作用域 (`scope`)
    • 参考

0. 写在前面

你好,我是 ZzzFatFish。这篇博客整理自我学习 Spring 框架的笔记。目前笔记只记录到一半,但内容恰好完整覆盖了 Spring 最核心、最基础、也是最重要的概念——控制反转 (IoC) 与依赖注入 (DI)。
即使在 Spring Boot 已成为主流的今天,深入理解 Spring Framework 的底层原理依然是 Java 开发者进阶的必经之路。希望这份笔记能帮助正在学习 Spring 的你,理清思路,夯实基础。
学习是一个持续迭代的过程,本文后续会继续更新。所有笔记对应的源码都已上传至我的 Gitee 仓库,欢迎 Star 和交流!

📦 对应代码仓库:https://gitee.com/zzzfatfish/spring-test
✍ 作者:fatfish
🕒 状态:学习中,内容持续补充完善…

1. Spring 核心概念

1.1 简介

Spring 的寓意
Spring,意为“春天”,旨在为软件开发带来春天般的生机与活力。

发展历史

  • 2002年:Rod Johnson(悉尼大学音乐学博士)发布了 Spring 框架的雏形——Interface21 框架。
  • 2004年:在 Interface21 的基础上,经过重新设计和功能丰富,Spring 1.0 正式版发布。
  • 核心理念:Spring 的目标是让现有的 Java 技术(如 Java EE)更加易于使用。它本身是一个集大成者,通过整合各种优秀的开源框架,为开发者提供一站式的解决方案。

经典技术栈

  • SSH: Struts2 + Spring + Hibernate
  • SSM: Spring MVC + Spring + MyBatis

相关资源

  • 官网: https://spring.io/
  • 项目主页: https://spring.io/projects/spring-framework
  • 官方文档: Spring Framework Documentation
  • Maven 仓库: https://mvnrepository.com/

Maven 核心依赖示例
要在项目中使用 Spring,通常需要引入其模块依赖。例如,开发 Web 应用需要 spring-webmvc,使用 JDBC 需要 spring-jdbc

<!-- Spring Web MVC 模块,包含了核心容器、AOP、Web等功能 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.23</version> <!-- 建议使用较新的稳定版本 -->
</dependency><!-- Spring JDBC 模块,用于简化数据库操作 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.23</version>
</dependency>

1.2 优点

  • 开源免费:Spring 是一个开源的、免费的框架(容器)。
  • 轻量级与非侵入式
    • 轻量级:指其核心库体积小,对系统资源占用少,并且可以按需引入模块。
    • 非侵入式:应用中的对象(POJO)无需继承 Spring 特定的类或实现接口,保持了代码的独立性。
  • 两大核心
    • 控制反转 (IoC - Inversion of Control):将对象的创建权交给 Spring 容器管理。
    • 面向切面编程 (AOP - Aspect Oriented Programming):在不修改源码的情况下,对程序进行功能增强。
  • 生态强大
    • 提供强大的事务管理能力。
    • 能够轻松整合几乎所有主流的第三方框架(如 MyBatis, Hibernate, Quartz 等)。

总结:Spring 是一个以 IoC(控制反转)和 AOP(面向切面编程)为核心的,一站式的轻量级开源框架。

1.3 组成 (Spring Framework Modules)

Spring 框架是一个分层架构,由多个功能明确的模块组成,可以根据项目需求按需引入。其核心模块主要包括:

  1. Core Container (核心容器)

    • spring-core, spring-beans, spring-context, spring-expression
    • 这是 Spring 框架的基石,提供了 IoC 和 DI 的功能。BeanFactoryApplicationContext 是其核心接口。
  2. AOP & Aspects (面向切面编程)

    • spring-aop, spring-aspects
    • 提供了 AOP 的实现,允许开发者定义方法拦截器和切点,实现如日志、权限控制等横切关注点的功能。
  3. Data Access / Integration (数据访问与集成)

    • spring-jdbc: 简化了 JDBC 操作。
    • spring-orm: 集成了主流的 ORM 框架,如 Hibernate、JPA。
    • spring-tx: 提供了强大的声明式和编程式事务管理。
    • spring-jms, spring-messaging: 用于消息传递。
  4. Web

    • spring-web: 提供了基础的 Web 功能,如文件上传、HTTP 客户端等。
    • spring-webmvc: 包含了 Spring MVC 框架,用于构建 Web 应用程序。
    • spring-websocket: 支持 WebSocket 通信。

1.4 拓展

为什么现在还要学习 Spring?

虽然 Spring Boot 和 Spring Cloud 是目前的主流,但它们都是构建在 Spring Framework 之上的。

  • Spring Boot: 一个快速开发的脚手架,遵循“约定大于配置”的原则,极大地简化了 Spring 应用的配置和部署。
  • Spring Cloud: 基于 Spring Boot 的一套微服务治理工具集。

学习路径:深入理解 SpringSpring MVC 的原理,是掌握 Spring Boot 的前提。它是承上启下的关键。

Spring 的“弊端”
随着功能不断扩展,早期 Spring 的 XML 配置变得异常繁琐和复杂,导致项目难以维护,被戏称为“配置地狱”。Spring Boot 的出现正是为了解决这一问题,通过自动化配置让开发者回归到业务本身。


2. IoC 理论推导 (控制反转)

2.1 从一个实例开始理解

我们通过一个简单的例子来理解 IoC 的思想演变。假设我们有一个 UserService,它需要调用 UserDao 来获取数据。

项目结构:

  • UserDao (接口)
  • UserDaoImpl (实现类)
  • UserService (接口)
  • UserServiceImpl (实现类)
步骤一:传统开发方式(主动创建依赖)

UserDao 接口 & 实现

// com.github.subei.dao.UserDao
public interface UserDao {void getUser();
}// com.github.subei.dao.UserDaoImpl
public class UserDaoImpl implements UserDao {@Overridepublic void getUser() {System.out.println("默认实现:从数据库获取用户数据...");}
}

UserService 接口 & 实现

// com.github.subei.service.UserService
public interface UserService {void getUser();
}// com.github.subei.service.UserServiceImpl
import com.github.subei.dao.UserDao;
import com.github.subei.dao.UserDaoImpl;public class UserServiceImpl implements UserService {// 程序主动创建依赖对象,耦合度高private UserDao userDao = new UserDaoImpl();@Overridepublic void getUser() {userDao.getUser();}
}

测试类

// MyTest.java
import com.github.subei.service.UserServiceImpl;public class MyTest {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();userService.getUser();}
}

问题分析:在 UserServiceImpl 中,userDao 是通过 new UserDaoImpl() 直接创建的。如果此时客户需求变更,需要从 Oracle 数据库获取数据(UserDaoOracleImpl),我们必须修改 UserServiceImpl 的源代码。这种高耦合的方式在大型项目中是灾难性的。

步骤二:改进方式(通过 Setter 注入)

为了解决上述问题,我们不再让 UserServiceImpl 自己创建 UserDao,而是提供一个 Setter 方法,让外部来决定使用哪个实现。

修改 UserServiceImpl.java

// com.github.subei.service.UserServiceImpl
import com.github.subei.dao.UserDao;public class UserServiceImpl implements UserService {private UserDao userDao;// 提供一个 set 方法,用于接收外部传入的依赖对象public void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void getUser() {userDao.getUser();}
}

修改测试类
现在,我们可以在测试类中“注入”我们想要的 UserDao 实现。

// 假设我们新增了一个 UserDaoMySqlImpl
public class UserDaoMySqlImpl implements UserDao {@Overridepublic void getUser() {System.out.println("新实现:从MySQL获取用户数据...");}
}// MyTest.java
import com.github.subei.dao.UserDaoMySqlImpl;
import com.github.subei.service.UserServiceImpl;public class MyTest {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();// 关键改变:我们在这里决定并“注入”具体的实现userService.setUserDao(new UserDaoMySqlImpl());userService.getUser();}
}

思想转变

  • 之前UserServiceImpl 主动创建并控制它所依赖的 UserDao 对象。
  • 现在UserServiceImpl 失去了对 UserDao 的创建控制权,它只能被动地接收。控制权反转到了调用方(MyTest)手中。

这种思想就是 控制反转 (IoC) 的雏形。程序从主动创建依赖,变成了被动接收依赖,从而大大降低了组件之间的耦合度。

2.2 IoC 的本质

控制反转 (Inversion of Control, IoC) 是一种设计思想,而不是一种具体的技术。它的核心是将原本由程序代码直接操控的对象创建权,交由一个外部容器来管理

依赖注入 (Dependency Injection, DI)实现 IoC 最常见的方式。所谓“依赖注入”,就是指容器在运行时,动态地将某个对象所依赖的其它对象注入到该对象中。

总结

  1. 谁控制谁?

    • 传统方式:应用程序的组件(如 UserServiceImpl)控制它所依赖的对象(UserDaoImpl)的创建。
    • IoC 方式:IoC 容器(如 Spring 容器)控制了所有组件的创建。组件只负责声明自己的依赖,不负责创建。
  2. 控制什么?

    • 主要控制外部资源的获取,例如对象实例、文件、数据库连接等。
  3. 为何叫反转?

    • 因为获取依赖的方向反了。传统方式是组件主动去获取依赖,而 IoC 方式是容器将依赖“推送”或“注入”到组件中。
  4. Spring 如何实现 IoC?

    • Spring IoC 容器(ApplicationContext)在启动时,会读取配置元数据(XML 文件或注解)。
    • 根据元数据创建和装配所有的对象(在 Spring 中称为 Bean)。
    • 当应用程序需要某个对象时,直接从容器中获取即可,无需关心其创建过程和依赖关系。

通过 IoC,我们将对象的创建、管理和装配等繁杂工作交给了框架,使我们能更专注于业务逻辑的实现。这就是 Spring 框架的强大之处。

3. 第一个 Spring 程序 (HelloSpring)

通过一个简单的入门案例,我们来实际感受一下 Spring IoC 容器是如何工作的。

步骤 1: 创建实体类 Hello.java

这是一个普通的 POJO (Plain Old Java Object)。

package com.github.subei.pojo;public class Hello {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Hello{" +"name='" + name + '\'' +'}';}
}

步骤 2: 创建 Spring 配置文件 beans.xml

这个 XML 文件是 Spring IoC 容器的“蓝图”,它描述了需要容器管理的对象(Bean)以及它们之间的关系。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 使用 <bean> 标签告诉 Spring 创建一个对象。在 Spring 中,这些被管理的对象称为 Bean。id: Bean 的唯一标识符,相当于对象名。class: Bean 的全限定类名。--><bean id="hello" class="com.github.subei.pojo.Hello"><!-- 使用 <property> 标签为对象的属性赋值。name: 对应类中的属性名 (setter方法)。value: 要设置的具体值。--><property name="name" value="Spring"/></bean></beans>

步骤 3: 编写测试类

import com.github.subei.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest {public static void main(String[] args) {// 1. 获取 Spring 的上下文对象 (IoC 容器)// ClassPathXmlApplicationContext 会解析 beans.xml 文件, 创建并管理其中定义的 BeanApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");// 2. 从容器中获取我们需要的 Bean// context.getBean("id"),参数即为 Spring 配置文件中 bean 的 idHello hello = (Hello) context.getBean("hello");// 3. 使用对象System.out.println(hello.toString());}
}

核心概念回顾

  • Hello 对象是谁创建的?
    Hello 对象由 Spring IoC 容器创建,而不是我们手动 new 的。

  • Hello 对象的属性是怎么设置的?
    name 属性是在 beans.xml 中配置后,由 Spring 容器通过调用 setName() 方法注入的。

这个过程就是控制反转 (IoC) 的体现:

  • 控制:对 Hello 对象创建和管理的控制权。
  • 反转:控制权从我们的应用程序代码(手动 new)反转到了外部的 Spring 容器。

依赖注入 (DI) 则是实现 IoC 的一种方式,即容器将对象所需的依赖(如 name 属性值)通过 Setter 方法或构造函数注入进去。

将 IoC 应用于上一节的例子

现在,我们用 Spring 的方式来改造 UserServiceUserDao 的例子,彻底实现解耦。

beans.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans ...><!-- 把 UserDao 的两个实现类都交给 Spring 管理 --><bean id="mysqlImpl" class="com.github.subei.dao.UserDaoMySqlImpl"/><bean id="oracleImpl" class="com.github.subei.dao.UserDaoOracleImpl"/><!-- 配置 UserService --><bean id="userServiceImpl" class="com.github.subei.service.UserServiceImpl"><!-- 使用 ref 引用容器中已经存在的另一个 Bean。这里我们将 id 为 "mysqlImpl" 的 Bean 注入到 userDao 属性中。--><property name="userDao" ref="mysqlImpl"/></bean></beans>

测试类

@Test
public void testUserService() {ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");UserServiceImpl service = (UserServiceImpl) context.getBean("userServiceImpl");service.getUser(); // 输出:从MySQL获取用户数据...
}

优势:现在,如果想切换到 Oracle 数据库,我们只需修改 XML 配置文件,将 ref 的值从 mysqlImpl 改为 oracleImpl,而无需改动任何一行 Java 代码。这真正实现了“对象由 Spring 来创建、管理和装配”。


4. IoC 创建对象的方式

Spring 容器创建 Bean 主要通过反射机制,常见的方式有两种:

4.1 方式一:使用无参构造函数 (默认)

当我们在 XML 中只配置 <bean class="..."> 时,Spring 默认会调用该类的无参构造函数来创建实例。如果类中没有无参构造函数,Spring 容器会启动失败。

public class User {public User() {System.out.println("User 的无参构造函数被调用!");}// ... getters and setters
}

配置

<bean id="user" class="com.github.subei.pojo.User"><property name="name" value="Subei"/>
</bean>

结论:在 context.getBean("user") 之前,当 ApplicationContext 初始化的那一刻,User 对象就已经通过无参构造函数被创建好了。

4.2 方式二:使用有参构造函数

如果希望 Spring 使用有参构造函数来创建对象,需要使用 <constructor-arg> 标签明确指定构造函数的参数。

public class User {private String name;public User(String name) {this.name = name;System.out.println("User 的有参构造函数被调用!");}// ...
}

配置方式

<!-- 方式一:通过参数下标 (index) 指定,从 0 开始 -->
<bean id="user1" class="com.github.subei.pojo.User"><constructor-arg index="0" value="Subei_by_index"/>
</bean><!-- 方式二:通过参数类型 (type) 指定,不推荐,类型相同时会混淆 -->
<bean id="user2" class="com.github.subei.pojo.User"><constructor-arg type="java.lang.String" value="Subei_by_type"/>
</bean><!-- 方式三:通过参数名 (name) 指定,最推荐,直观且不易出错 -->
<bean id="user3" class="com.github.subei.pojo.User"><constructor-arg name="name" value="Subei_by_name"/>
</bean>

总结:在配置文件加载时,Spring 容器就会根据配置调用相应的构造函数来初始化 Bean。


5. Spring 配置详解

5.1 别名 (<alias>)

可以为一个 Bean 设置一个或多个别名,通过别名也能获取到同一个对象。

<bean id="user" class="com.github.subei.pojo.User" ... /><!-- 为 id="user" 的 bean 设置一个别名 "userNew" -->
<alias name="user" alias="userNew"/>

之后,context.getBean("user")context.getBean("userNew") 获取的是同一个实例。

5.2 Bean 的基本配置 (id, class, name)

<!--id:    Bean 的唯一标识符。命名规范遵循 XML ID 约束(不能以数字开头等)。class: Bean 的全限定类名。name:  也是别名。相比 <alias> 标签,name 属性可以一次性指定多个别名,用逗号(,)、分号(;)或空格分隔。name 属性命名更灵活,没有 id 的限制。
-->
<bean id="user" class="com.github.subei.pojo.User" name="u2, u3; u4"><property name="name" value="懒羊羊"/>
</bean>

context.getBean("user"), context.getBean("u2"), context.getBean("u3"), context.getBean("u4") 都能获取到这个 Bean。

5.3 导入其他配置 (<import>)

在团队开发或大型项目中,为了便于管理,通常会将 Spring 配置拆分成多个文件(如按模块 spring-dao.xml, spring-service.xml)。可以使用 <import> 标签将它们组合起来。

<!-- 在主配置文件 applicationContext.xml 中 -->
<beans ...><import resource="spring-dao.xml"/><import resource="spring-service.xml"/><import resource="spring-controller.xml"/>
</beans>

6. 依赖注入 (DI)

依赖注入是 IoC 的具体实现。它的核心思想是:

  • 依赖:Bean 的创建和运行依赖于 Spring 容器。
  • 注入:Bean 的属性(包括基本类型和对象类型)由 Spring 容器来设置和装配。

6.1 构造器注入

已在 4.2 节中介绍,通过 <constructor-arg> 标签实现。

6.2 Set 注入 (重点)

通过调用属性的 setter 方法进行注入,使用 <property> 标签实现。这是最常用、最直观的注入方式。

示例环境

// 地址类
public class Address {private String address;// ... getter, setter, toString
}// 学生类,包含各种类型的属性
public class Student {private String name;          // 普通字符串private Address address;      // 其他 Bean 对象private String[] books;       // 数组private List<String> hobbies; // List 集合private Map<String, String> card; // Map 集合private Set<String> games;    // Set 集合private Properties info;      // Propertiesprivate String wife;          // 用于测试 null// ... 所有属性的 getter, setter, toString
}

XML 配置大全

<beans><!-- 先配置一个 Address Bean --><bean id="address" class="com.github.subei.pojo.Address"><property name="address" value="成都市武侯区"/></bean><bean id="student" class="com.github.subei.pojo.Student"><!-- 1. 普通值/字面量注入:使用 value 属性 --><property name="name" value="小明"/><!-- 2. Bean 注入 (引用另一个Bean):使用 ref 属性 --><property name="address" ref="address"/><!-- 3. 数组注入:使用 <array> 和 <value> --><property name="books"><array><value>《Java核心技术》</value><value>《深入理解JVM》</value></array></property><!-- 4. List 注入:使用 <list> 和 <value> --><property name="hobbies"><list><value>编程</value><value>游戏</value></list></property><!-- 5. Map 注入:使用 <map> 和 <entry> --><property name="card"><map><entry key="身份证" value="510..."/><entry key="银行卡" value="622..."/></map></property><!-- 6. Set 注入:使用 <set> 和 <value> --><property name="games"><set><value>LOL</value><value>CS:GO</value></set></property><!-- 7. Properties 注入:使用 <props> 和 <prop> --><property name="info"><props><prop key="学号">2023001</prop><prop key="性别"></prop></props></property><!-- 8. null 值注入:使用 <null/> --><property name="wife"><null/></property></bean>
</beans>

6.3 拓展方式注入 (p-命名空间和c-命名空间)

为了简化 XML 配置,Spring 提供了 pc 命名空间,它们是 <property><constructor-arg> 的简写形式。

使用前准备:必须在 <beans> 根标签中引入对应的命名空间。

<?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:p="http://www.springframework.org/schema/p"  <!-- 引入p命名空间 -->xmlns:c="http://www.springframework.org/schema/c"  <!-- 引入c命名空间 -->xsi:schemaLocation="..."><!-- p-命名空间注入 (本质是 set 注入) --><!-- p:属性名="值"  p:引用属性名-ref="引用的beanId" --><bean id="user" class="com.github.subei.pojo.User" p:name="subei" p:age="21"/><!-- c-命名空间注入 (本质是构造器注入, 需要有对应的有参构造) --><!-- c:构造器参数名="值" --><bean id="user2" class="com.github.subei.pojo.User" c:name="subei" c:age="22"/></beans>

6.4 Bean 的作用域 (scope)

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象。

Bean 的作用域定义了 Spring 容器如何创建和管理 Bean 实例的生命周期。通过在 <bean> 标签中设置 scope 属性来指定。

Scope描述
singleton(默认) 在整个 Spring IoC 容器中,该 Bean 只有一个实例。
prototype每次请求(如 getBean())时,都会创建一个新的 Bean 实例。
request每次 HTTP 请求,创建一个新实例。仅在 Web 应用中有效。
session每个 HTTP Session,创建一个新实例。仅在 Web 应用中有效。
applicationServletContext 的生命周期内,只创建一个实例。仅在 Web 应用中有效。
websocketwebsocket 的生命周期内,只创建一个实例。仅在 Web 应用中有效。

1. Singleton (单例模式)
这是 Spring 的默认行为。容器启动时就创建好实例,以后每次获取都是同一个。

<bean id="user" class="com.github.subei.pojo.User" scope="singleton"/>

测试:

User user1 = context.getBean("user", User.class);
User user2 = context.getBean("user", User.class);
System.out.println(user1 == user2); // 输出: true

2. Prototype (原型模式)
每次从容器获取时,都会创建一个全新的对象。适用于有状态的 Bean。

<bean id="user" class="com.github.subei.pojo.User" scope="prototype"/>

测试:

User user1 = context.getBean("user", User.class);
User user2 = context.getBean("user", User.class);
System.out.println(user1 == user2); // 输出: false

3. Request
Spring 容器通过为每个 HTTP 请求使用loginAction bean 定义来创建LoginAction bean 的新实例。也就是说,loginAction bean 的作用域是 HTTP 请求级别。您可以根据需要更改创建实例的内部状态,因为从同一loginAction bean 定义创建的其他实例看不到这些状态更改。它们特定于单个请求。当请求完成处理时,将限制作用于该请求的 Bean。

考虑以下 XML 配置来定义 bean :

<bean id="loginAction" class="com.something.LoginAction" scope="request"/>

使用注解驱动的组件或 Java 配置时,可以使用@RequestScope注解 将组件分配给request范围。以下示例显示了如何执行此操作:

@RequestScope
@Component
public class LoginAction {// ...
}

4、Section

当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

考虑下面bean定义:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

在单个 HTTP Session的生存期内,Spring 容器通过使用userPreferences bean 定义来创建UserPreferences bean 的新实例。换句话说,userPreferences bean 的作用域实际上是 HTTP Session级别。与请求范围的 Bean 一样,您可以根据需要任意更改所创建实例的内部状态,因为知道其他 HTTP Session实例(也使用从相同userPreferences Bean 定义创建的实例)不会看到这些状态更改,因为它们特定于单个 HTTP Session。当最终丢弃 HTTP Session时,也将丢弃作用于该特定 HTTP Session的 bean。

@SessionScope
@Component
public class UserPreferences {// ...
}

参考

【狂神说Java】Spring5最新完整教程IDEA版通俗易懂
Spring学习目录(6天) - subeiLY - 博客园

http://www.lryc.cn/news/620131.html

相关文章:

  • AWS Bedrock Claude模型费用深度分析:企业AI成本优化指南
  • HarmonyOS Navigation路由跳转的完整示例
  • 天猫商品评论API:获取商品热门评价与最新评价
  • 销售数据预处理与分析学习总结
  • 基于UniApp的智能在线客服系统前端设计与实现
  • Github desktop介绍(GitHub官方推出的一款图形化桌面工具,旨在简化Git和GitHub的使用流程)
  • 公司项目用户密码加密方案推荐(兼顾安全、可靠与通用性)
  • Python day43
  • 【易错题】C语言
  • NTUSER.DAT是什么文件
  • Vue内置组件全解析:从入门到面试通关
  • docker安装centos
  • 接口添加了 @Transactional 注解并开启事务,而其中一个小方法启动了新线程并手动提交数据,会有什么影响?
  • 服务器安全笔记
  • 学习:JS进阶[10]内置构造函数
  • [ 数据结构 ] 泛型 (上)
  • Excel多级数据结构导入导出工具
  • Laravel 使用ssh链接远程数据库
  • Linux Framebuffer(帧缓冲)与基本 UI 绘制技术
  • 【R语言】RStudio 中的 Source on Save、Run、Source 辨析
  • 认知系统的架构: 认知残余三角形、认知主体意识 和认知演进金字塔
  • 【docker①】在VS Code中使用Docker容器
  • 从零用 NumPy 实现单层 Transformer 解码器(Decoder-Only)
  • 未来AI:微算法科技(NASDAQ:MLGO)开发基于忆阻器网络储层计算MemristorPattern虚拟平台
  • 通过限制网络访问来降低服务器被攻击风险的方法
  • 云原生技术k8s部署prometheus
  • 面向Python/C#开发者入门Java与Bukkit API
  • C# 反射和特性(元数据和反射)
  • Mysql——如何做到Redolog崩溃后恢复的
  • NLP学习之Transformer(1)