Spring相关知识

Spring相关知识

Spring Boot

SpringBoot比Spring好在哪里

  • Spring Boot 提供了自动化配置,大大简化了项目的配置过程。通过约定优于配置的原则,很多常用的配置可以自动完成,开发者可以专注于业务逻辑的实现。
  • Spring Boot 提供了快速的项目启动器,通过引入不同的 Starter,可以快速集成常用的框架和库(如数据库、消息队列、Web 开发等),极大地提高了开发效率。
  • Spring Boot 默认集成了多种内嵌服务器(如Tomcat、Jetty、Undertow),无需额外配置,即可将应用打包成可执行的 JAR 文件,方便部署和运行。

Spring Boot用到的设计模式

  • 代理模式:Spring 的 AOP 通过动态代理实现方法级别的切面增强,有静态和动态两种代理方式,采用动态代理方式。
  • 策略模式:Spring AOP 支持 JDK 和 Cglib 两种动态代理实现方式,通过策略接口和不同策略类,运行时动态选择,其创建一般通过工厂方法实现。
  • 单例模式:Spring Bean 默认是单例模式,通过单例注册表(如 HashMap)实现。
  • 简单工厂模式:Spring 中的 BeanFactory 是简单工厂模式的体现,通过工厂类方法获取 Bean 实例。
  • 适配器模式:Spring MVC 中针对不同方式定义的 Controller,利用适配器模式统一函数定义,定义了统一接口 HandlerAdapter 及对应适配器类。

怎么理解SpringBoot中的约定大于配置

在传统的Spring开发中,开发者需要手动编写大量的XML或Java配置代码来初始化各种组件。而Spring Boot通过“约定优于配置”(Convention Over Configuration)原则,提供了一套默认的配置和行为,让开发者只需关注业务逻辑,除非有特殊需求才需要手动修改配置。

  • 自动配置机制(Auto-Configuration):Spring Boot会根据项目中引入的依赖自动推断所需的配置。例如,引入Spring Web依赖时,它会自动配置Tomcat、Spring MVC等组件。核心注解是@EnableAutoConfiguration,它通过AutoConfigurationImportSelector加载所有可能的自动配置类。
  • 默认配置文件位置和命名:Spring Boot默认读取application.properties或application.yml作为配置文件,位置在src/main/resources目录下。只要遵循这个约定,就能自动加载配置。
  • 起步依赖(Starter Dependencies):Spring Boot提供了一系列“starter”,如spring-boot-starter-web、spring-boot-starter-data-jpa等。这些starter封装了常用依赖和默认配置,开发者只需引入一个starter即可获得完整功能。
  • 项目结构约定:默认扫描主类所在包及其子包下的组件(如@Controller、@Service等),只要遵循包结构约定即可自动注册Bean。

SpringBoot自动装配原理是什么?2.x

  • 核心靠@EnableAutoConfiguration注解,这个注解导入了一个类,AutoConfigurationImportSelector,这个类会通过SpringFactoriesLoader扫描项目里所有依赖包下的META-INF/spring.factories文件,里面列举了一系列配置类,spring boot启动时会把这些类按需加载进来,因为这些类通常配置了一系列条件注解,满足才配置

说几个启动器(starter)?

  • spring-boot-starter-web:这是最常用的起步依赖之一,它包含了Spring MVC和Tomcat嵌入式服务器,用于快速构建Web应用程序。
  • spring-boot-starter-security:提供了Spring Security的基本配置,帮助开发者快速实现应用的安全性,包括认证和授权功能。
  • mybatis-spring-boot-starter:这个Starter是由MyBatis团队提供的,用于简化在Spring Boot应用中集成MyBatis的过程。它自动配置了MyBatis的相关组件,包括SqlSessionFactory、MapperScannerConfigurer等,使得开发者能够快速地开始使用MyBatis进行数据库操作。
  • spring-boot-starter-data-jpa 或 spring-boot-starter-jdbc:如果使用的是Java Persistence API (JPA)进行数据库操作,那么应该使用spring-boot-starter-data-jpa。这个Starter包含了Hibernate等JPA实现以及数据库连接池等必要的库,可以让你轻松地与MySQL数据库进行交互。你需要在application.properties或application.yml中配置MySQL的连接信息。如果倾向于直接使用JDBC而不通过JPA,那么可以使用spring-boot-starter-jdbc,它提供了基本的JDBC支持。
  • spring-boot-starter-data-redis:用于集成Redis缓存和数据存储服务。这个Starter包含了与Redis交互所需的客户端(默认是Jedis客户端,也可以配置为Lettuce客户端),以及Spring Data Redis的支持,使得在Spring Boot应用中使用Redis变得非常便捷。同样地,需要在配置文件中设置Redis服务器的连接详情。
  • spring-boot-starter-test:包含了单元测试和集成测试所需的库,如JUnit, Spring Test, AssertJ等,便于进行测试驱动开发(TDD)。

SpringBoot里面有哪些重要的注解?还有一个配置相关的注解是哪个?

  • @SpringBootApplication:用于标注主应用程序类,标识一个Spring Boot应用程序的入口点,同时启用自动配置和组件扫描。
  • @Controller:标识控制器类,处理HTTP请求。
  • @RestController:结合@Controller和@ResponseBody,返回RESTful风格的数据。
  • @Service:标识服务类,通常用于标记业务逻辑层。
  • @Repository:标识数据访问组件,通常用于标记数据访问层。
  • @Component:通用的Spring组件注解,表示一个受Spring管理的组件。
  • @Autowired:用于自动装配Spring Bean。
  • @Value:用于注入配置属性值。
  • @RequestMapping:用于映射HTTP请求路径到Controller的处理方法。
  • @GetMapping、@PostMapping、@PutMapping、@DeleteMapping:简化@RequestMapping的GET、POST、PUT和DELETE请求。
    另外,一个与配置相关的重要注解是:
  • @Configuration:用于指定一个类为配置类,其中定义的bean会被Spring容器管理。通常与@Bean配合使用,@Bean用于声明一个Bean实例,由Spring容器进行管理。

Springboot怎么做到导入就可以直接使用的?

这个主要依赖于自动配置、起步依赖和条件注解等特性。

起步依赖

  • 起步依赖是一种特殊的 Maven 或 Gradle 依赖,它将项目所需的一系列依赖打包在一起。例如,spring-boot-starter-web 这个起步依赖就包含了 Spring Web MVC、Tomcat 等构建 Web 应用所需的核心依赖。
  • 开发者只需在项目中添加一个起步依赖,Maven 或 Gradle 就会自动下载并管理与之关联的所有依赖,避免了手动添加大量依赖的繁琐过程。

自动配置

  • Spring Boot 的自动配置机制会根据类路径下的依赖和开发者的配置,自动创建和配置应用所需的 Bean。它通过 @EnableAutoConfiguration 注解启用,该注解会触发 Spring Boot 去查找 META - INF/spring.factories 文件。
  • spring.factories 文件中定义了一系列自动配置类,Spring Boot 会根据当前项目的依赖情况,选择合适的自动配置类进行加载。例如,如果项目中包含 spring-boot-starter-web 依赖,Spring Boot 会加载 WebMvcAutoConfiguration 类,该类会自动配置 Spring MVC 的相关组件,如 DispatcherServlet、视图解析器等。
  • 开发者可以通过自定义配置来覆盖自动配置的默认行为。如果开发者在 application.properties 或 application.yml 中定义了特定的配置,或者在代码中定义了同名的 Bean,Spring Boot 会优先使用开发者的配置。

条件注解

  • 条件注解用于控制 Bean 的创建和加载,只有在满足特定条件时,才会创建相应的 Bean。Spring Boot 的自动配置类中广泛使用了条件注解,如 @ConditionalOnClass、@ConditionalOnMissingBean 等。
  • 比如,@ConditionalOnClass 表示只有当类路径中存在指定的类时,才会创建该 Bean。例如,在 WebMvcAutoConfiguration 类中,可能会有如下代码:
    1
    2
    3
    4
    5
    @Configuration
    @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
    public class WebMvcAutoConfiguration {
    // 配置相关的 Bean
    }
  • 这段代码表示只有当类路径中存在 Servlet、DispatcherServlet 和 WebMvcConfigurer 类时,才会加载 WebMvcAutoConfiguration 类中的配置。

SpringBoot 过滤器和拦截器说一下?

对比维度 过滤器(Filter) 拦截器(Interceptor)
规范来源 Java EE Servlet 规范 Spring MVC 框架机制
依赖关系 不依赖 Spring 容器 完全依赖 Spring 容器
作用范围 所有请求,包括静态资源 仅处理 Controller 请求
执行时机 在 DispatcherServlet 之前执行 在DispatcherServlet之后、Controller方法前后执行
生命周期管理 Servlet 容器管理(init、doFilter、destroy) Spring 管理(preHandle、postHandle、afterCompletion)
配置方式 @WebFilter 注解或注册 Bean 实现 HandlerInterceptor 接口并注册到 WebMvcConfigurer
典型用途 编码设置、日志记录、安全校验、跨域处理等 权限验证、用户登录状态检查、业务逻辑拦截等

与传统的JDBC相比,MyBatis的优点?

  • 基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任 何影响,SQL 写在 XML 里,解除 sql 与程序代码的耦合,便于统一管理;提供 XML 标签,支持编写动态 SQL 语句,并可重用。
  • 与 JDBC 相比,减少了 50%以上的代码量,消除了 JDBC 大量冗余的代码,不 需要手动开关连接;
  • 很好的与各种数据库兼容,因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数据库 MyBatis 都支持。
  • 能够与 Spring 很好的集成,开发效率高
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射 标签,支持对象关系组件维护。

MyBatis觉得在哪方面做的比较好?

  • SQL 与代码解耦,灵活可控:MyBatis 允许开发者直接编写和优化 SQL,相比全自动 ORM(如 Hibernate),MyBatis 让开发者明确知道每条 SQL 的执行逻辑,便于性能调优。
  • 动态 SQL 的强大支持:比如可以动态拼接SQL,通过 <if>, <choose>, <foreach> 等标签动态生成 SQL,避免 Java 代码中繁琐的字符串拼接。
    1
    2
    3
    4
    5
    6
    7
    <select id="searchUsers" resultType="User">
    SELECT * FROM user
    <where>
    <if test="name != null">AND name LIKE #{name}</if>
    <if test="status != null">AND status = #{status}</if>
    </where>
    </select>
  • 自动映射与自定义映射结合:自动将查询结果字段名与对象属性名匹配(如驼峰转换)。
    1
    2
    3
    4
    5
    6
    7
    <resultMap id="userRoleMap" type="User">
    <id property="id" column="user_id"/>
    <result property="name" column="user_name"/>
    <collection property="roles" ofType="Role">
    <result property="roleName" column="role_name"/>
    </collection>
    </resultMap>
  • 与 Spring 生态无缝集成:通过 @MapperScan 快速扫描 Mapper 接口,结合 Spring 事务管理,配置简洁高效。

Mybatis里的 # 和 $ 的区别?

  • Mybatis 在处理 #{} 时,会创建预编译的 SQL 语句,将 SQL 中的 #{} 替换为 ? 号,在执行 SQL 时会为预编译 SQL 中的占位符(?)赋值,调用 PreparedStatement 的 set 方法来赋值,预编译的 SQL 语句执行效率高,并且可以防止SQL 注入,提供更高的安全性,适合传递参数值。
  • Mybatis 在处理 ${} 时,只是创建普通的 SQL 语句,然后在执行 SQL 语句时 MyBatis 将参数直接拼入到 SQL 里,不能防止 SQL 注入,因为参数直接拼接到 SQL 语句中,如果参数未经过验证、过滤,可能会导致安全问题。

MybatisPlus和Mybatis的区别?

MybatisPlus是一个基于MyBatis的增强工具库,旨在简化开发并提高效率。

  • CRUD操作:MybatisPlus通过继承BaseMapper接口,提供了一系列内置的快捷方法,使得CRUD操作更加简单,无需编写重复的SQL语句。
  • 代码生成器:MybatisPlus提供了代码生成器功能,可以根据数据库表结构自动生成实体类、Mapper接口以及XML映射文件,减少了手动编写的工作量。
  • 通用方法封装:MybatisPlus封装了许多常用的方法,如条件构造器、排序、分页查询等,简化了开发过程,提高了开发效率。
  • 分页插件:MybatisPlus内置了分页插件,支持各种数据库的分页查询,开发者可以轻松实现分页功能,而在传统的MyBatis中,需要开发者自己手动实现分页逻辑。

Spring

说说对Spring的理解

  • Spring 是一个以 IoC(控制反转)和 AOP(面向切面编程)为核心思想的 Java 企业级开发基础框架

说说Spring IoC和AOP

IoC

  • 控制反转。传统开发过程中,我们需要通过new关键字来创建对象。使用IoC思想开发方式的话,我们不通过new关键字创建对象,而是通过IoC容器来帮我们实例化对象。 通过IoC的方式,可以大大降低对象之间的耦合度。

AOP

  • 是面向切面编程,能够将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,以减少系统的重复代码,降低模块间的耦合度。Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理。
  • AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

二者结合

  • 通过 IOC 容器管理对象的依赖关系,然后通过 AOP 将横切关注点统一切入到需要的业务逻辑中。
  • 使用 IOC 容器管理 Service 层和 DAO 层的依赖关系,然后通过 AOP 在 Service 层实现事务管理、日志记录等横切功能,使得业务逻辑更加清晰和可维护。

IOC和AOP是通过什么机制来实现的?

IoC

  • 反射:Spring IOC容器利用Java的反射机制动态地加载类、创建对象实例及调用对象方法,反射允许在运行时检查类、方法、属性等信息,从而实现灵活的对象实例化和管理。
  • 依赖注入:IOC的核心概念是依赖注入,即容器负责管理应用程序组件之间的依赖关系。Spring通过构造函数注入、属性注入或方法注入,将组件之间的依赖关系描述在配置文件中或使用注解。
  • 容器实现:Spring IOC容器是实现IOC的核心,通常使用BeanFactory或ApplicationContext来管理Bean。BeanFactory是IOC容器的基本形式,提供基本的IOC功能;ApplicationContext是BeanFactory的扩展,并提供更多企业级功能。
  • 设计模式:工厂模式,Spring IOC容器通常采用工厂模式来管理对象的创建和生命周期。容器作为工厂负责实例化Bean并管理它们的生命周期,将Bean的实例化过程交给容器来管理。

AOP

  • 动态代理技术
  • 基于JDK的动态代理:使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。这种方式需要代理的类实现一个或多个接口。
  • 基于CGLIB的动态代理:当被代理的类没有实现接口时,Spring会使用CGLIB库生成一个被代理类的子类作为代理。CGLIB(Code Generation Library)是一个第三方代码生成库,通过继承方式实现代理。

依赖倒置,依赖注入,控制反转分别是什么?

  • 控制反转:“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。
  • 依赖注入:依赖注入和控制反转恰恰相反,它是一种具体的编码技巧。我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。
  • 依赖倒置:这条原则跟控制反转有点类似,主要用来指导框架层面的设计。高层模块不依赖低层模块,它们共同依赖同一个抽象。抽象不要依赖具体实现细节,具体实现细节依赖抽象。

如果让你设计一个SpringIoc,你觉得会从哪些方面考虑这个设计?

  • Bean的生命周期管理:需要设计Bean的创建、初始化、销毁等生命周期管理机制,可以考虑使用工厂模式和单例模式来实现。
  • 依赖注入:需要实现依赖注入的功能,包括属性注入、构造函数注入、方法注入等,可以考虑使用反射机制和XML配置文件来实现。
  • Bean的作用域:需要支持多种Bean作用域,比如单例、原型、会话、请求等,可以考虑使用Map来存储不同作用域的Bean实例。
  • AOP功能的支持:需要支持AOP功能,可以考虑使用动态代理机制和切面编程来实现。
  • 异常处理:需要考虑异常处理机制,包括Bean创建异常、依赖注入异常等,可以考虑使用try-catch机制来处理异常。
  • 配置文件加载:需要支持从不同的配置文件中加载Bean的相关信息,可以考虑使用XML、注解或者Java配置类来实现。

bean的创建过程(IOC容器的创建过程)

IOC容器加载过程

  • 创建容器:new ApplicationContext
  • 读取bean定义信息,并转化为多个beanDefinition对象,并注册到beanDefinitionMap(一个哈希表)中
  • 一个个创建bean,需要判断是否懒加载,是否单例bean

创建

  • 实例化:使用反射,从beanDefinition获取beanclass
  • 属性注入
  • 初始化
  • 缓存到一级缓存(单例池,如果是单例)

动态代理

  • 动态代理是在运行时动态生成代理对象,而不是在编译时。它允许开发者在运行时指定要代理的接口和行为,从而实现在不修改源码的情况下增强方法的功能。
  • 若代理的类实现了接口,使用JDK动态代理,没有实现则使用CGLIB

三级缓存解决循环依赖

循环依赖问题

  • 第一种:通过构造方法进行依赖注入时产生的循环依赖问题。
  • 第二种:通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
  • 第三种:通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。
  • 解决的是第三种

三级缓存

  • singletonObjects (一级缓存):存放的是完全初始化好的、可用的 Bean 实例,getBean() 方法最终返回的就是这里面的 Bean。此时 Bean 已实例化、属性已填充、初始化方法已执行、AOP 代理(如果需要)也已生成。
  • earlySingletonObjects (二级缓存):存放的是提前暴露的 Bean 的原始对象引用 或 早期代理对象引用,专门用来处理循环依赖。当一个 Bean 还在创建过程中(尚未完成属性填充和初始化),但它的引用需要被注入到另一个 Bean 时,就暂时放在这里。此时 Bean 已实例化(调用了构造函数),但属性尚未填充,初始化方法尚未执行,它可能是一个原始对象,也可能是一个为了解决 AOP 代理问题而提前生成的代理对象。
  • singletonFactories (三级缓存):存放的是 Bean 的 ObjectFactory 工厂对象。,这是解决循环依赖和 AOP 代理协同工作的关键。当 Bean 被实例化后(刚调完构造函数),Spring 会创建一个 ObjectFactory 并将其放入三级缓存。这个工厂的 getObject() 方法负责返回该 Bean 的早期引用(可能是原始对象,也可能是提前生成的代理对象),当检测到循环依赖需要注入一个尚未完全初始化的 Bean 时,就会调用这个工厂来获取早期引用。

过程

  • 1️⃣ 创建 Bean A
    • Spring 开始创建 Bean A 的实例(构造函数执行)
    • 此时还未注入属性,也未初始化
    • Spring 将一个 ObjectFactory(可能生成代理对象) 放入 三级缓存
  • 2️⃣ Bean A 依赖 Bean B → 创建 Bean B
    • Spring发现 Bean A 依赖 Bean B,开始创建 Bean B
    • 同样放入 Bean B 的 ObjectFactory 到三级缓存
  • 3️⃣ Bean B 依赖 Bean A → 需要获取 Bean A 的引用
    • Spring 调用 getBean(“A”),发现 Bean A 正在创建中
    • 查找缓存:
      • 一级缓存:没有
      • 二级缓存:没有
      • 三级缓存:找到了 Bean A 的 ObjectFactory
  • 4️⃣ 通过 ObjectFactory 获取 Bean A 的早期引用
    • Spring 调用 ObjectFactory 的 getObject() 方法
    • 此时会判断是否需要 AOP 代理:
      • ✅ 如果需要 → 创建代理对象(JDK 或 CGLIB)
      • ❌ 如果不需要 → 返回原始实例
    • 将代理对象放入 二级缓存
  • 5️⃣ Bean B 注入 Bean A 的代理对象
    • Bean B 完成属性注入和初始化
    • 放入一级缓存
  • 6️⃣ 回到 Bean A,完成注入和初始化
    • Bean A 注入 Bean B 的完整引用
    • Bean A 完成初始化
    • 放入一级缓存(此时是代理对象)

spring三级缓存的数据结构是什么?

都是 Map类型的缓存,比如Map {k:name; v:bean}。

  • 一级缓存(Singleton Objects):这是一个Map类型的缓存,存储的是已经完全初始化好的bean,即完全准备好可以使用的bean实例。键是bean的名称,值是bean的实例。这个缓存在DefaultSingletonBeanRegistry类中的singletonObjects属性中。
  • 二级缓存(Early Singleton Objects):这同样是一个Map类型的缓存,存储的是早期的bean引用,即已经实例化但还未完全初始化的bean。这些bean已经被实例化,但是可能还没有进行属性注入等操作。这个缓存在DefaultSingletonBeanRegistry类中的earlySingletonObjects属性中。
  • 三级缓存(Singleton Factories):这也是一个Map类型的缓存,存储的是ObjectFactory对象,这些对象可以生成早期的bean引用。当一个bean正在创建过程中,如果它被其他bean依赖,那么这个正在创建的bean就会通过这个ObjectFactory来创建一个早期引用,从而解决循环依赖的问题。这个缓存在DefaultSingletonBeanRegistry类中的singletonFactories属性中。

spring框架中都用到了哪些设计模式

  • 工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
  • 代理设计模式 : Spring AOP 功能的实现。
  • 单例设计模式 : Spring 中的 Bean 默认都是单例的。
  • 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
  • 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
  • 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  • 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。

spring 常用注解有什么?

@Autowired 注解

  • 主要用于自动装配bean。当Spring容器中存在与要注入的属性类型匹配的bean时,它会自动将bean注入到属性中。就跟我们new 对象一样。

@Component

  • 这个注解用于标记一个类作为Spring的bean。当一个类被@Component注解标记时,Spring会将其实例化为一个bean,并将其添加到Spring容器中。

@Configuration

  • 用于标记一个类作为Spring的配置类。配置类可以包含@Bean注解的方法,用于定义和配置bean,作为全局配置。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Configuration
    public class MyConfiguration {

    @Bean
    public MyBean myBean() {
    return new MyBean();
    }

    }

@Bean

  • 用于标记一个方法作为Spring的bean工厂方法。当一个方法被@Bean注解标记时,Spring会将该方法的返回值作为一个bean,并将其添加到Spring容器中,如果自定义配置,经常用到这个注解。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Configuration
    public class MyConfiguration {

    @Bean
    public MyBean myBean() {
    return new MyBean();

    }
    }

Spring的事务什么情况下会失效?

  • 未捕获异常: 如果一个事务方法中发生了未捕获的异常,并且异常未被处理或传播到事务边界之外,那么事务会失效,所有的数据库操作会回滚。
  • 非受检异常: 默认情况下,Spring对非受检异常(RuntimeException或其子类)进行回滚处理,这意味着当事务方法中抛出这些异常时,事务会回滚。
  • 事务传播属性设置不当: 如果在多个事务之间存在事务嵌套,且事务传播属性配置不正确,可能导致事务失效。特别是在方法内部调用有 @Transactional 注解的方法时要特别注意。
  • 多数据源的事务管理: 如果在使用多数据源时,事务管理没有正确配置或者存在多个 @Transactional 注解时,可能会导致事务失效。
  • 跨方法调用事务问题: 如果一个事务方法内部调用另一个方法,而这个被调用的方法没有 @Transactional 注解,这种情况下外层事务可能会失效。
  • 事务在非公开方法中失效: 如果 @Transactional 注解标注在私有方法上或者非 public 方法上,事务也会失效。

Spring的事务,使用this调用是否生效?

  • 不能生效。
  • 因为Spring事务是通过代理对象来控制的,只有通过代理对象的方法调用才会应用事务管理的相关规则。当使用this直接调用时,是绕过了Spring的代理机制,因此不会应用事务设置。

Bean是否单例?

  • Spring 中的 Bean 默认都是单例的。
  • 就是说,每个Bean的实例只会被创建一次,并且会被存储在Spring容器的缓存中,以便在后续的请求中重复使用。这种单例模式可以提高应用程序的性能和内存效率。
  • 但是,Spring也支持将Bean设置为多例模式,即每次请求都会创建一个新的Bean实例。要将Bean设置为多例模式,可以在Bean定义中通过设置scope属性为”prototype”来实现。
  • 需要注意的是,虽然Spring的默认行为是将Bean设置为单例模式,但在一些情况下,使用多例模式是更为合适的,例如在创建状态不可变的Bean或有状态Bean时。此外,需要注意的是,如果Bean单例是有状态的,那么在使用时需要考虑线程安全性问题。

Bean的单例和非单例,生命周期是否一样

  • 不一样的,Spring Bean 的生命周期完全由 IoC 容器控制。Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 Bean,Spring 在创建好交给使用者之后,则不会再管理后续的生命周期。
  • 单例bean在容器启动时/首次请求时 创建,非单例bean在每次请求时创建新实例
  • 单例bean在容器关闭时销毁,非单例bean容器不管理销毁,需由调用者自行释放资源(Spring不跟踪实例)。
  • 单例bean适用于无状态服务(如Service、DAO层)。非单例bean适用于有状态对象(如用户会话、临时计算对象)。

Spring bean的作用域有哪些?

可以通过@Scope注解来指定Bean的作用域

  • Singleton(单例):在整个应用程序中只存在一个 Bean 实例。默认作用域,Spring 容器中只会创建一个 Bean 实例,并在容器的整个生命周期中共享该实例。
  • Prototype(原型):每次请求时都会创建一个新的 Bean 实例。次从容器中获取该 Bean 时都会创建一个新实例,适用于状态非常瞬时的 Bean。
  • Request(请求):每个 HTTP 请求都会创建一个新的 Bean 实例。仅在 Spring Web 应用程序中有效,每个 HTTP 请求都会创建一个新的 Bean 实例,适用于 Web 应用中需求局部性的 Bean。
  • Session(会话):Session 范围内只会创建一个 Bean 实例。该 Bean 实例在用户会话范围内共享,仅在 Spring Web 应用程序中有效,适用于与用户会话相关的 Bean。
  • Application:当前 ServletContext 中只存在一个 Bean 实例。仅在 Spring Web 应用程序中有效,该 Bean 实例在整个 ServletContext 范围内共享,适用于应用程序范围内共享的 Bean。
  • WebSocket(Web套接字):在 WebSocket 范围内只存在一个 Bean 实例。仅在支持 WebSocket 的应用程序中有效,该 Bean 实例在 WebSocket 会话范围内共享,适用于 WebSocket 会话范围内共享的 Bean。
  • Custom scopes(自定义作用域):Spring 允许开发者定义自定义的作用域,通过实现 Scope 接口来创建新的 Bean 作用域。

Spring容器里存的是什么?

  • 在Spring容器中,存储的主要是Bean对象。
  • Bean是Spring框架中的基本组件,用于表示应用程序中的各种对象。当应用程序启动时,Spring容器会根据配置文件或注解的方式创建和管理这些Bean对象。Spring容器会负责创建、初始化、注入依赖以及销毁Bean对象。

在Spring中,在bean加载/销毁前后,如果想实现某些逻辑,可以怎么做

使用init-method和destroy-method

  • 在XML配置中,你可以通过init-method和destroy-method属性来指定Bean初始化后和销毁前需要调用的方法。
    1
    2
    <bean id="myBean" class="com.example.MyBeanClass"  
    init-method="init" destroy-method="destroy"/>
  • 然后在Bean类中实现

实现InitializingBean和DisposableBean接口

  • 你的Bean类可以实现org.springframework.beans.factory.InitializingBean和org.springframework.beans.factory.DisposableBean接口,并分别实现afterPropertiesSet和destroy方法。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class MyBeanClass implements InitializingBean, DisposableBean {  

    @Override
    public void afterPropertiesSet() throws Exception {
    // 初始化逻辑
    }

    @Override
    public void destroy() throws Exception {
    // 销毁逻辑
    }
    }

使用@PostConstruct和@PreDestroy注解

1
2
3
4
5
6
7
8
9
10
11
12
public class MyBeanClass {  

@PostConstruct
public void init() {
// 初始化逻辑
}

@PreDestroy
public void destroy() {
// 销毁逻辑
}
}

使用@Bean注解的initMethod和destroyMethod属性

1
2
3
4
5
6
7
8
@Configuration  
public class AppConfig {

@Bean(initMethod = "init", destroyMethod = "destroy")
public MyBeanClass myBean() {
return new MyBeanClass();
}
}

Spring给我们提供了很多扩展点,这些有了解吗?

  • BeanFactoryPostProcessor:允许在Spring容器实例化bean之前修改bean的定义。常用于修改bean属性或改变bean的作用域。
  • BeanPostProcessor:可以在bean实例化、配置以及初始化之后对其进行额外处理。常用于代理bean、修改bean属性等。
  • PropertySource:用于定义不同的属性源,如文件、数据库等,以便在Spring应用中使用。
  • ImportSelector和ImportBeanDefinitionRegistrar:用于根据条件动态注册bean定义,实现配置类的模块化。
  • Spring MVC中的HandlerInterceptor:用于拦截处理请求,可以在请求处理前、处理中和处理后执行特定逻辑。
  • Spring MVC中的ControllerAdvice:用于全局处理控制器的异常、数据绑定和数据校验。
  • Spring Boot的自动配置:通过创建自定义的自动配置类,可以实现对框架和第三方库的自动配置。
  • 自定义注解:创建自定义注解,用于实现特定功能或约定,如权限控制、日志记录等。

Spring相关知识
https://sdueryrg.github.io/2025/09/11/Spring相关知识/
作者
yrg
发布于
2025年9月11日
许可协议