Java开发框架:Spring IOC、Bean

Spring框架

我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。

比如说 Spring 支持 IoC(Inversion of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程)、可以很方便地对数据库进行访问、可以很方便地集成第三方组件(电子邮件,任务,调度,缓存等等)、对单元测试支持比较好、支持 RESTful Java 应用程序的开发。

Spring框架的核心模块

Core Container

Spring框架的核心模块,主要提供IoC依赖注入功能的支持。Spring其他所有的功能都依赖该模块

  • spring-core:Spring框架的核心工具类

  • spring-beans:提供对bean的创建、配置和管理等都功能的支持

  • spring-context:提供对国际化、事件传播、资源加载等功能的支持

  • spring-expression:提供对表达式语言的支持,只依赖于core模块,可以单独使用。

AoP

  • spring-aspects:该模块为于AspectJ的集成提供支持。

  • spring-apo:提供了面向切面的编程实现。

  • spring-instrument:提供了为JVM添加代理的功能。使用场景非常有限。

Data Access/Integration

  • spring-jdbc:提供了对数据库访问的抽象JDBC。不同的数据库都有自己独立的API用于操作数据库,Java程序只需要和API交互,屏蔽了数据库的影响。

  • spring-tx:提供对事物的支持

  • spring-orm:提供对Hibernate、JPA、iBatis等ORM框架的支持。

  • spring-oxm:

  • spring-jsm:消息服务。

Spring Web

  • spring-web:对 Web 功能的实现提供一些最基础的支持。

  • spring-webmvc:提供对 Spring MVC 的实现。主要赋予 Spring 快速构建 MVC 架构的 Web 程序的能力。MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。

  • spring-websocket:提供了对 WebSocket 的支持,WebSocket 可以让客户端和服务端进行双向通信。

  • spring-webflux:提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步。

IOC思想

Spring IOC(Inversion of Control:控制反转)的思想是将创建对象的控制权交由Spring框架来管理。之前都是通过new的方式手动创建对象,在使用Spring框架之后,可以通过XML配置好需要的对象或者在SpringBoot中通过注解的方式配置,使用的时候直接引用就好了。

在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。

DI(依赖注入)

依赖注入(DI) 是IOC思想的一种实现方式。Spring容器也是通过这种形式管理Bean的。比如:A类要依赖B类,A类不再直接创建B类的实例,而是把这种依赖关系配置在外部xml文件或者通过注解配置依赖关系,然后由Spring容器根据配置信息创建、管理bean类。

BeanFactory和ApplicationContext

BeanFactory和ApplicationContext是Spring的两大核心接口,ApplicationContext是BeanFactory的子接口。

bean什么时候被实例化

  • 如果使用BeanFactory作为Spring Bean的工厂类,则所有的Bean都是在第一次使用该Bean(调用getBean)的时候实例化。

    • 这种方式无法发现一些Spring的配置问题。如果bean的某一个属性没有注入,BeanFactory加载后,直至第一次调用getBean方法才会抛出异常。
  • 如果使用ApplicationFactory作为工厂类,则分为以下情况:

    • 如果bean是singleton的,并且lazy-init为false,则ApplicationContext启动的时候就实例化该Bean,并且将实例化的bean放在一个map结构的缓存中,下次再用的时候直接从缓存中获取。

    • 如果scope是singleton,且lazy-init为true或者使用@Lazy注解将其设置为懒加载模式,则:容器在解析注册Bean定义时进行预实例化??

    • 如果scope是prototype,则在第一次使用该bean的时候实例化。

Bean的作用域有哪些

  • singleton:单例,Ioc容器中只有唯一的bean实例。

  • prototype:每次获取都会创建一个新的bean实例。也就是说,连续getBean()两次,得到的是不同的实例。

  • request:仅web应用可用。每次http请求都会产生一个新的bean,且仅在当前http request内生效

  • session:仅web应用可用。每次来自新session的http请求都会产生一个新的bean,仅在当前http session内有效。

  • application/gloable-session:仅web应用可用。每个web应用在启动时创建一个bean,仅在启动时间。

  • websocket:每次websocket回话产生一个新的bean。

如何配置bean的作用域

xml方式

xml 复制代码
<bean id = "..." class="..." scope="singleton"></bean>

注解方式:

java 复制代码
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Persion personPrototype(){
    return new Person();
}

Bean是否线程安全

Spring 框架中的 Bean 是否线程安全,取决于其作用域和状态。

最常用的两种作用域 是prototype 和 singleton 。几乎所有场景的 Bean 作用域都是使用默认的 singleton ,重点关注 singleton 作用域即可。

  • prototype 作用域下,每次获取都会创建一个新的 bean 实例,不存在资源竞争问题,所以不存在线程安全问题。
  • singleton 作用域下,IoC 容器中只有唯一的 bean 实例,可能会存在资源竞争问题(取决于 Bean 是否有状态)。
    • 如果这个 bean 是有状态的话,那就存在线程安全问题(有状态 Bean 是指包含可变的成员变量的对象)
    • 不过,大部分 Bean 实际都是无状态(没有定义可变的成员变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。

对于有状态单例 Bean 的线程安全问题,常见的有两种解决办法:

  1. 在 Bean 中尽量避免定义可变的成员变量。
  2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

Bean的生命周期

这个部分还需要再详细学习一下。

参考文章

  1. JavaGuide面试题
  2. 一文彻底明白IOC及Bean
相关推荐
炒空心菜菜5 小时前
SparkSQL 连接 MySQL 并添加新数据:实战指南
大数据·开发语言·数据库·后端·mysql·spark
蜗牛沐雨7 小时前
Rust 中的 `PartialEq` 和 `Eq`:深入解析与应用
开发语言·后端·rust
Python私教7 小时前
Rust快速入门:从零到实战指南
开发语言·后端·rust
秋野酱8 小时前
基于javaweb的SpringBoot爱游旅行平台设计和实现(源码+文档+部署讲解)
java·spring boot·后端
小明.杨8 小时前
Django 中时区的理解
后端·python·django
有梦想的攻城狮8 小时前
spring中的@Async注解详解
java·后端·spring·异步·async注解
qq_12498707538 小时前
原生小程序+springboot+vue医院医患纠纷管理系统的设计与开发(程序+论文+讲解+安装+售后)
java·数据库·spring boot·后端·小程序·毕业设计
lybugproducer9 小时前
浅谈 Redis 数据类型
java·数据库·redis·后端·链表·缓存
焚 城9 小时前
.NET8关于ORM的一次思考
后端·.net
撸猫79111 小时前
HttpSession 的运行原理
前端·后端·cookie·httpsession