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
相关推荐
希冀12322 分钟前
【操作系统】1.2操作系统的发展与分类
后端
GoppViper1 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
爱上语文2 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people2 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
罗政7 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
拾光师9 小时前
spring获取当前request
java·后端·spring
Java小白笔记10 小时前
关于使用Mybatis-Plus 自动填充功能失效问题
spring boot·后端·mybatis
JOJO___12 小时前
Spring IoC 配置类 总结
java·后端·spring·java-ee
白总Server13 小时前
MySQL在大数据场景应用
大数据·开发语言·数据库·后端·mysql·golang·php
Lingbug14 小时前
.Net日志组件之NLog的使用和配置
后端·c#·.net·.netcore