欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?IOC功能詳解

 更新時間:2025年06月04日 09:38:05   作者:?abc!  
在Java開發(fā)中,Ioc意味著將你設(shè)計好的對象交給容器控制,而不是傳統(tǒng)的在你的對象內(nèi)部直接控制,本文給大家介紹Spring?IOC的相關(guān)知識,感興趣的朋友一起看看吧

概述

為什么叫控制反轉(zhuǎn)

Spring Bean是什么:Spring里面的bean就類似是定義的一個組件,而這個組件的作用就是實(shí)現(xiàn)某個功能的,這里所定義的bean就相當(dāng)于給了你一個更為簡便的方法來調(diào)用這個組件去實(shí)現(xiàn)你要完成的功能

Spring框架管理這些Bean的創(chuàng)建工作,即由用戶管理Bean轉(zhuǎn)變?yōu)榭蚣芄芾鞡ean,這個就叫控制反轉(zhuǎn) - Inversion of Control (IoC)

  • 這些托管創(chuàng)建的Bean放在IoC Container
  • 為了更好讓用戶配置Bean,引入不同方式來配置Bean:xml配置,Java配置,注解配置等支持
  • Spring也管理整個Bean的生命周期
  • 應(yīng)用程序代碼從Ioc Container中獲取依賴的Bean,注入到應(yīng)用程序中,這個過程叫 依賴注入(Dependency Injection,DI)

控制反轉(zhuǎn)是通過依賴注入實(shí)現(xiàn)的,IoC是設(shè)計思想,DI是實(shí)現(xiàn)方式

IOC不是什么技術(shù),是一種設(shè)計思想。

在Java開發(fā)中,Ioc意味著將你設(shè)計好的對象交給容器控制,而不是傳統(tǒng)的在你的對象內(nèi)部直接控制。

  • 正轉(zhuǎn):傳統(tǒng)應(yīng)用程序是由我們自己在對象中主動控制去直接獲取依賴對象
  • 反轉(zhuǎn):由容器來幫忙創(chuàng)建及注入依賴對象
  • 由IoC容器幫對象找相應(yīng)的依賴對象并注入,而不是由對象主動去找

Spring 中的 bean 的作用域

基礎(chǔ)概念

singleton : 唯一 bean 實(shí)例,Spring 中的 bean 默認(rèn)都是單例的。
prototype : 每次請求都會創(chuàng)建一個新的 bean 實(shí)例。

Spring并不管理作用域?yàn)閜rototype的bean的整個生命周期,使用者必須自己銷毀 這個bean并釋放資源。

下述作用域只有在web環(huán)境下才有用

  • request : 每一次 HTTP 請求都會產(chǎn)生一個新的 bean,該 bean 僅在當(dāng)前 HTTP request 內(nèi)有效。
  • session : 每一次 HTTP 請求都會產(chǎn)生一個新的 bean,該 bean 僅在當(dāng)前 HTTP session 內(nèi)有效。
  • global-session: 全局 session 作用域,僅僅在基于 Portlet 的 web 應(yīng)用中才有意義,Spring5 已經(jīng)沒有了
  • Portlet 是能夠生成語義代碼(例如:HTML)片段的小型 Java Web 插件。它們基于 portlet 容器,可以像 servlet 一樣處理 HTTP 請求。但是,與 servlet 不同,每個 portlet 都有不同的會話

對比

作用域說明典型應(yīng)用場景
singleton默認(rèn)作用域,容器內(nèi)唯一實(shí)例無狀態(tài)Service、工具類
prototype每次注入創(chuàng)建新實(shí)例有狀態(tài)Bean、含可變狀態(tài)的組件
request每個HTTP請求創(chuàng)建新實(shí)例Web請求上下文相關(guān)對象
session每個用戶會話創(chuàng)建新實(shí)例用戶購物車、登錄信息
application整個Web應(yīng)用生命周期單例全局配置

有狀態(tài)和無狀態(tài)的bean

基本概念

在 Spring 框架中,有狀態(tài) Bean 和 無狀態(tài) Bean 是兩種重要的對象設(shè)計模式,它們的核心區(qū)別在于 是否保存可變狀態(tài),直接影響線程安全性和作用域管理

有狀態(tài) Bean 注意事項(xiàng)

  • 作用域控制:必須顯式聲明作用域(如 @Scope(“prototype”))。
  • 避免單例陷阱:禁止在單例 Bean 中注入有狀態(tài) Bean(除非使用 ThreadLocal)。
  • 防御性編程:返回數(shù)據(jù)時返回副本而非引用

無狀態(tài) Bean 最佳實(shí)踐

  • 方法參數(shù)化:所有數(shù)據(jù)通過方法參數(shù)傳遞。
  • 依賴注入:通過構(gòu)造函數(shù)注入其他 Bean。
  • 工具類設(shè)計:將狀態(tài)抽取到參數(shù)中

建議

  • 優(yōu)先無狀態(tài)設(shè)計:90%的業(yè)務(wù)場景應(yīng)使用無狀態(tài)Bean
  • 有狀態(tài)Bean最小化:必須使用時有明確的作用域控制
  • 避免混合狀態(tài):不要在同一Bean中混用有狀態(tài)和無狀態(tài)代碼

對比

特征有狀態(tài) Bean無狀態(tài) Bean
實(shí)例變量/狀態(tài)存儲包含可變的成員變量(會隨操作改變)無成員變量,或只有不可變常量
線程安全需自行保證線程安全(如加鎖、隔離)天然線程安全(無共享狀態(tài))
作用域通常用 prototype 作用域(每次注入新實(shí)例)通常用 singleton 作用域(全局共享)
復(fù)用性不同請求需不同實(shí)例(需頻繁創(chuàng)建實(shí)例)、資源消耗較高全局共享單個實(shí)例、高性能(單例復(fù)用)
典型場景用戶會話、購物車、事務(wù)上下文工具類、Service層業(yè)務(wù)邏輯

Ioc 配置的三種方式

總體上目前的主流方式是: 注解 + Java 配置

xml 配置

將bean的信息配置.xml文件里,通過Spring加載文件為我們創(chuàng)建bean。

  • 優(yōu)點(diǎn): 可以使用于任何場景,結(jié)構(gòu)清晰,通俗易懂
  • 缺點(diǎn): 配置繁瑣,不易維護(hù),枯燥無味,擴(kuò)展性差
<?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/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- services -->
    <bean id="userService" class="com.service.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>
    <!-- more bean definitions for services go here -->
</beans>

Java 配置

將類的創(chuàng)建交給我們配置的JavcConfig類來完成,Spring只負(fù)責(zé)維護(hù)和管理,采用純Java創(chuàng)建方式。其本質(zhì)上就是把在XML上的配置聲明轉(zhuǎn)移到Java配置類中

  • 優(yōu)點(diǎn):適用于任何場景,配置方便,因?yàn)槭羌僇ava代碼,擴(kuò)展性高,十分靈活
  • 缺點(diǎn):由于是采用Java類的方式,聲明不明顯,如果大量配置,可讀性比較差
@Configuration
public class BeansConfig {
    /**
     * @return user dao
     */
    @Bean("userDao")
    public UserDaoImpl userDao() {
        return new UserDaoImpl();
    }
    /**
     * @return user service
     */
    @Bean("userService")
    public UserServiceImpl userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao());
        return userService;
    }
}

注解配置

通過在類上加注解的方式,來聲明一個類交給Spring管理,Spring會自動掃描帶有@Component,@Controller,@Service,@Repository這四個注解的類,然后幫我們創(chuàng)建并管理,前提是需要先配置Spring的注解掃描器。

  • 優(yōu)點(diǎn):開發(fā)便捷,通俗易懂,方便維護(hù)。
  • 缺點(diǎn):具有局限性,對于一些第三方資源,無法添加注解。只能采用XML或JavaConfig的方式配置

依賴注入的三種方式

常用的注入方式主要有三種:構(gòu)造方法注入(Construct注入),setter注入,基于注解的注入(接口注入)

setter方式

通過對應(yīng)變量的setXXX()方法以及在方法上面使用注解,來完成依賴注入。
Setter方法注入是通過在類中提供setter方法來注入依賴項(xiàng)的。Spring容器會調(diào)用這些setter方法來設(shè)置依賴項(xiàng)的值。這種方式更加靈活,因?yàn)榭梢栽趯ο髣?chuàng)建后的任何時候注入依賴項(xiàng)。

比如:在 Spring 4.3 及以后的版本中,setter 上面的 @Autowired 注解是可以不寫的。

private Helper helper;
@Autowired
public void setHelper(Helper helper) {
    this.helper = helper;
}

優(yōu)點(diǎn):

  • 可以在對象創(chuàng)建后的任何時候注入依賴項(xiàng)。
  • 可以重新配置已存在的對象。

缺點(diǎn):

  • 可能導(dǎo)致對象狀態(tài)的不確定性,因?yàn)橐蕾図?xiàng)可以在任何時候被更改。
  • 不支持不可變對象。

構(gòu)造方法注入

將各個必需的依賴全部放在帶有注解構(gòu)造方法的參數(shù)中,并在構(gòu)造方法中完成對應(yīng)變量的初始化,這種方式,就是基于構(gòu)造方法的注入。
比如:在 Spring 4.3 及以后的版本中,如果這個類只有一個構(gòu)造方法,那么這個構(gòu)造方法上面也可以不寫 @Autowired 注解。

private final Svc svc;
@Autowired
public HelpService(@Qualifier("svcB") Svc svc) {
    this.svc = svc;
}

優(yōu)點(diǎn):

  • 確保依賴項(xiàng)在對象創(chuàng)建時就被初始化。
  • 可以設(shè)置依賴項(xiàng)為final,確保它們不會被修改。
  • 支持不可變對象。

缺點(diǎn):

  • 如果類有很多依賴項(xiàng),構(gòu)造函數(shù)可能會變得很長且難以閱讀

基于注解(字段)的注入

示例

public class MyService {
    @Autowired
    private MyRepository repository;
}

優(yōu)點(diǎn):

  • 代碼簡單明了,易于實(shí)現(xiàn)。

缺點(diǎn):根據(jù)Spring官方的建議,推薦使用構(gòu)造器注入和Setter注入,而盡量避免使用字段注入。字段注入被認(rèn)為是一種不太理想的方式,因?yàn)樗哂幸韵氯秉c(diǎn):

  • 不利于不變性:與構(gòu)造器注入不同,字段注入無法將不變的依賴關(guān)系傳遞給組件,因?yàn)樽侄慰梢栽谌魏螘r候更改。
  • 可見性問題:外部無法明確看到組件所依賴的內(nèi)容,因?yàn)橐蕾囮P(guān)系被隱藏在組件內(nèi)部。這可能導(dǎo)致代碼可讀性下降。
  • 緊密綁定:字段注入會導(dǎo)致組件與IoC容器緊密綁定,使組件在沒有容器的情況下難以使用,也使單元測試更加復(fù)雜。
  • 不明顯的依賴關(guān)系:當(dāng)依賴關(guān)系變得復(fù)雜時,使用字段注入可能導(dǎo)致依賴關(guān)系不夠明顯,難以理解組件的需求。

推薦@Resource而不是@Autowired注解

  • @Resource具有更廣泛的兼容性
    • @Autowired是Spring特定的注解,與Spring框架緊密相關(guān)。如果以后決定更換不同的IoC容器,那么@Autowired可能不再適用,因?yàn)槠渌萜骺赡懿恢С炙?/li>
    • @Resource是Java標(biāo)準(zhǔn)(JSR-250)提供的注解,幾乎所有的IoC容器都會支持它。因此,即使你將來更換了容器,使用@Resource的代碼仍然可以正常工作,不需要類似的警告。
  • 提高了代碼的可移植性:認(rèn)為@Resource更符合Java的標(biāo)準(zhǔn)化。

IOC設(shè)計體系

流程圖

IOC初始化流程

  • 初始化的入口在容器實(shí)現(xiàn)中的 refresh()調(diào)用來完成
  • 對 bean 定義載入 IOC 容器使用的方法是 loadBeanDefinition,其中的大致過程如下:
    • 通過 ResourceLoader 來完成資源文件位置的定位,bean 定義文件時通過抽象成 Resource 來被 IOC 容器處理的
    • 通過 BeanDefinitionReader來完成定義信息的解析和 Bean 信息的注冊
    • 容器解析得到 BeanDefinition 以后,需要把它在 IOC 容器中注冊,這由 IOC 實(shí)現(xiàn) BeanDefinitionRegistry 接口來實(shí)現(xiàn)。
    • 注冊過程就是在 IOC 容器內(nèi)部維護(hù)的一個HashMap 來保存得到的 BeanDefinition 的過程
    • 這個 HashMap 是 IoC 容器持有 bean 信息的場所,以后對 bean 的操作都是圍繞這個HashMap 來實(shí)現(xiàn)的.
    • 流程圖如下:

  • 然后我們就可以通過 BeanFactory 和 ApplicationContext 來享受到 Spring IOC 的服務(wù)了

Bean實(shí)例化(生命周期,循環(huán)依賴等)

最終的將Bean的定義即BeanDefinition放到beanDefinitionMap中,本質(zhì)上是一個ConcurrentHashMap<String, Object>;
并且BeanDefinition接口中包含了這個類的Class信息以及是否是單例等;

解決循環(huán)依賴問題

Spring如何解決循環(huán)依賴問題

Spring只是解決了單例模式下屬性依賴的循環(huán)問題:Spring為了解決單例的循環(huán)依賴問題,使用了三級緩存。

三級緩存詳細(xì):見這篇

Spring為什么不能解決多例的循環(huán)依賴:多實(shí)例Bean是每次調(diào)用一次getBean都會執(zhí)行一次構(gòu)造方法并且給屬性賦值,根本沒有三級緩存,因此不能解決循環(huán)依賴。

  • 這類循環(huán)依賴問題可以通過把bean改成單例的解決。

Spring為什么不能解決prototype作用域循環(huán)依賴:spring不會緩存prototype作用域的bean,而spring中循環(huán)依賴的解決正是通過緩存來實(shí)現(xiàn)的。

  • 這類循環(huán)依賴問題可以通過使用@Lazy注解解決。 生成代理對象產(chǎn)生的循環(huán)依賴

生成代理對象產(chǎn)生的循環(huán)依賴,解決方法很多,主要有:

  • 使用@Lazy注解,延遲加載
  • 使用@DependsOn注解,指定加載先后關(guān)系
  • 修改文件名稱,改變循環(huán)依賴類的加載順序

使用@DependsOn產(chǎn)生的循環(huán)依賴:這類循環(huán)依賴問題要找到@DependsOn注解循環(huán)依賴的地方,迫使它不循環(huán)依賴就可以解決問題。

Spring中Bean的生命周期

Spring 只幫我們管理單例模式 Bean 的完整生命周期,對于 prototype 的 bean ,Spring 在創(chuàng)建好交給使用者之后則不會再管理后續(xù)的生命周期。

  • prototype 是一種 bean 的作用域。它的主要特點(diǎn)是每次請求都會創(chuàng)建一個新的 bean 實(shí)例。
  • 與 singleton 作用域不同,singleton只會創(chuàng)建一個共享的實(shí)例

Bean的完整生命周期經(jīng)歷了各種方法調(diào)用,這些方法可以劃分為以下幾類:(結(jié)合上圖,需要有如下頂層思維)

  • Bean自身的方法: 這個包括了Bean本身調(diào)用的方法和通過配置文件中的init-method和destroy-method指定的方法
  • Bean級生命周期接口方法: 這個包括了BeanNameAware、BeanFactoryAware、ApplicationContextAware;當(dāng)然也包括InitializingBean和DiposableBean這些接口的方法(可以被@PostConstruct和@PreDestroy注解替代)
  • 容器級生命周期接口方法: 這個包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個接口實(shí)現(xiàn),一般稱它們的實(shí)現(xiàn)類為“后處理器”。
  • 工廠后處理器接口方法: 這個包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工廠后處理器接口的方法。工廠后處理器也是容器級的。在應(yīng)用上下文裝配配置文件之后立即調(diào)用

到此這篇關(guān)于Spring IOC詳解的文章就介紹到這了,更多相關(guān)Spring IOC詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring@Autowired與@Resource的區(qū)別有哪些

    Spring@Autowired與@Resource的區(qū)別有哪些

    這篇文章主要為大家詳細(xì)介紹了@Autowired與@Resource的區(qū)別,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Java創(chuàng)建可執(zhí)行JAR文件的多種方式

    Java創(chuàng)建可執(zhí)行JAR文件的多種方式

    本文主要介紹了Java創(chuàng)建可執(zhí)行JAR文件的多種方式,使用JDK的jar工具、IDE、Maven和Gradle來創(chuàng)建和配置可執(zhí)行JAR文件,具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • 基于mybatis like %%的問題

    基于mybatis like %%的問題

    這篇文章主要介紹了mybatis like %%的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 業(yè)務(wù)系統(tǒng)的Prometheus實(shí)踐示例詳解

    業(yè)務(wù)系統(tǒng)的Prometheus實(shí)踐示例詳解

    這篇文章主要為大家介紹了業(yè)務(wù)系統(tǒng)的Prometheus實(shí)踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Java實(shí)現(xiàn)一個簡易聊天室流程

    Java實(shí)現(xiàn)一個簡易聊天室流程

    這篇文章主要介紹了我的java課程設(shè)計一個多人聊天室(socket+多線程)本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-11-11
  • java遠(yuǎn)程調(diào)用接口、URL的方式代碼

    java遠(yuǎn)程調(diào)用接口、URL的方式代碼

    我們都知道接口有自己本地的,也有遠(yuǎn)程別人寫好的,而調(diào)用遠(yuǎn)程接口的就需要使用遠(yuǎn)程調(diào)用啦,這篇文章主要給大家介紹了關(guān)于java遠(yuǎn)程調(diào)用接口、URL的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • springboot項(xiàng)目如何設(shè)置session的過期時間

    springboot項(xiàng)目如何設(shè)置session的過期時間

    這篇文章主要介紹了springboot項(xiàng)目如何設(shè)置session的過期時間,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java8如何構(gòu)建一個Stream示例詳解

    Java8如何構(gòu)建一個Stream示例詳解

    Java 8 是迄今為止在語義上改動上最大的一個平臺。下面這篇文章主要給大家介紹了關(guān)于Java8如何構(gòu)建一個Stream的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-04-04
  • Java實(shí)現(xiàn)微信掃碼登入的實(shí)例代碼

    Java實(shí)現(xiàn)微信掃碼登入的實(shí)例代碼

    這篇文章主要介紹了java實(shí)現(xiàn)微信掃碼登入功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • java中如何區(qū)分==和equals

    java中如何區(qū)分==和equals

    這篇文章主要介紹了java中如何區(qū)分==和equals,文中講解的非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07

最新評論