1. 程式人生 > >你真的懂Spring Java Config 嗎?Full @Configuration vs lite @Bean mode

你真的懂Spring Java Config 嗎?Full @Configuration vs lite @Bean mode

Full @Configurationlite @Bean mode 是 Spring Java Config 中兩個非常有意思的概念。

先來看一下官方文件關於這兩者的相關內容:

The @Bean methods in a regular Spring component are processed differently than their counterparts inside a Spring @Configuration class. The difference is that @Component classes are not enhanced with CGLIB to intercept the invocation of methods and fields. CGLIB proxying is the means by which invoking methods or fields within @Bean methods in @Configuration classes creates bean metadata references to collaborating objects. Such methods are not invoked with normal Java semantics but rather go through the container in order to provide the usual lifecycle management and proxying of Spring beans, even when referring to other beans through programmatic calls to @Bean methods. In contrast, invoking a method or field in a @Bean method within a plain @Component class has standard Java semantics, with no special CGLIB processing or other constraints applying.

機器翻譯結果:常規Spring元件中的@Bean方法與Spring @Configuration類中的對應方法處理方式不同。不同之處在於,@Component類沒有使用CGLIB增強來攔截方法和欄位的呼叫。CGLIB代理是通過呼叫@Configuration類中的@Bean方法中的方法或欄位來建立對協作物件的bean元資料引用的方法。這些方法不是用普通的Java語義呼叫的,而是通過容器來提供Spring bean通常的生命週期管理和代理,即使在通過對@Bean方法的程式設計呼叫引用其他bean時也是如此。相反,在普通@Component類中呼叫@Bean方法中的方法或欄位具有標準的Java語義,不需要使用特殊的CGLIB處理或其他約束。

When @Bean methods are declared within classes that are not annotated with @Configuration, they are referred to as being processed in a “lite” mode. Bean methods declared in a @Component or even in a plain old class are considered to be “lite”, with a different primary purpose of the containing class and a @Bean method being a sort of bonus there. For example, service components may expose management views to the container through an additional @Bean method on each applicable component class. In such scenarios, @Bean methods are a general-purpose factory method mechanism. Unlike full @Configuration, lite @Bean methods cannot declare inter-bean dependencies. Instead, they operate on their containing component’s internal state and, optionally, on arguments that they may declare. Such a @Bean method should therefore not invoke other @Bean methods. Each such method is literally only a factory method for a particular bean reference, without any special runtime semantics. The positive side-effect here is that no CGLIB subclassing has to be applied at runtime, so there are no limitations in terms of class design (that is, the containing class may be final and so forth). In common scenarios, @Bean methods are to be declared within @Configuration classes, ensuring that “full” mode is always used and that cross-method references therefore get redirected to the container’s lifecycle management. This prevents the same @Bean method from accidentally being invoked through a regular Java call, which helps to reduce subtle bugs that can be hard to track down when operating in “lite” mode.

機器翻譯:當@Bean方法在沒有使用@Configuration註釋的類中宣告時,它們被稱為在“lite”模式下處理。在@Component中宣告的Bean方法,甚至在普通的舊類中宣告的Bean方法,都被認為是“lite”,包含類的主要目的不同,而@Bean方法在這裡是一種附加功能。例如,服務元件可以通過每個適用元件類上的附加@Bean方法向容器公開管理檢視。在這種情況下,@Bean方法是一種通用的工廠方法機制。與完整的@Configuration不同,lite @Bean方法不能宣告bean之間的依賴關係。相反,它們對包含它們的元件的內部狀態進行操作,並可選地對它們可能宣告的引數進行操作。因此,這樣的@Bean方法不應該呼叫其他@Bean方法。每個這樣的方法實際上只是一個特定bean引用的工廠方法,沒有任何特殊的執行時語義。這裡的積極副作用是在執行時不需要應用CGLIB子類,所以在類設計方面沒有限制(也就是說,包含的類可能是final類,等等)。在常見的場景中,@Bean方法將在@Configuration類中宣告,以確保始終使用“full”模式,並因此將交叉方法引用重定向到容器的生命週期管理。這可以防止通過常規Java呼叫意外呼叫相同的@Bean方法,這有助於減少在“lite”模式下操作時難以跟蹤的細微bug。


相關定義

  • lite @Bean mode :當@Bean方法在沒有使用@Configuration註解的類中宣告時稱之為lite @Bean mode
  • Full @Configuration:如果@Bean方法在使用@Configuration註解的類中宣告時稱之為Full @Configuration

有何區別

總結一句話,Full @Configuration中的@Bean方法會被CGLIB所代理,而 lite @Bean mode中的@Bean方法不會被CGLIB代理。

舉個例子

有一普通Java類,現在分別使用Full @Configurationlite @Bean mode這兩種模式註冊到Spring容器中。

public class User {
    public User() {
        System.out.println("user create... hashCode :" + this.hashCode());
    }
}

Full @Configuration

配置類:

@Configuration
public class AppConfig {

    @Bean
    public User user() {
        return new User();
    }

    @Bean
    public String name(User user) {
        System.out.println(user.hashCode());
        System.out.println(user().hashCode());
        return "123";
    }
}

主程式:

public class FullMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = context.getBean(User.class);
        System.out.println(user.hashCode());
        context.close();
    }
}

執行結果:

user create... hashCode :1709537756
1709537756
1709537756
1709537756

分析:@Bean是在使用了@Configuration註解的類上被宣告的,屬於Full @Configuration@Configuration類中的@Bean地方會被CGLIB進行代理。Spring會攔截該方法的執行,在預設單例情況下,容器中只有一個Bean,所以我們多次呼叫user()方法,獲取的都是同一個物件。

注意:被CGLIB的方法是不能被宣告為privatefinal,因為CGLIB是通過生成子類來實現代理的,privatefinal方法是不能被子類Override的,也就是說,Full @Configuration模式下,@Bean的方法是不能不能被宣告為privatefinal,不然在啟動時Spring會直接報錯。

lite @Bean mode

配置類:

@Component
public class LiteAppConfig {

    @Bean
    public User user() {
        System.out.println("user() 方法執行");
        return new User();
    }

    @Bean
    public String name(User user) {
        System.out.println("name(User user) 方法執行");
        System.out.println(user.hashCode());
        System.out.println("再次呼叫user()方法: " + user().hashCode());
        return "123";
    }
}

主程式:

public class LiteMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LiteAppConfig.class);
        User user = context.getBean(User.class);
        System.out.println(user.hashCode());
        context.close();
    }
}

執行結果:

user() 方法執行
user create... hashCode :254413710
name(User user) 方法執行
254413710
user() 方法執行
user create... hashCode :1793329556
再次呼叫user()方法: 1793329556
254413710

分析:在lite @Bean mode模式下, @Bean方法不會被CGLIB代理,所以多次呼叫user()會生成多個user物件。

使用建議

為了防止出現一些奇怪的問題,建議都使用Full @Configuration


歡迎關注個人公眾號:

相關推薦

真的Spring Java Config Full @Configuration vs lite @Bean mode

Full @Configuration和lite @Bean mode 是 Spring Java Config 中兩個非常有意思的概念。 先來看一下官方文件關於這兩者的相關內容: The @Bean methods in a regular Spring component are processed d

五分鐘學Java:一篇文章帶spring全家桶套餐

原創宣告 本文首發於微信公眾號【程式設計師黃小斜】 本文作者:黃小斜 轉載請務必在文章開頭註明出處和作者。 本文思維導圖 什麼是Spring,為什麼你要學習spring? 你第一次接觸spring框架是在什麼時候?相信很多人和我一樣,第一次瞭解spring都不是做專案的時候用到,而是在網上看到或者是聽到過

真的let和const

es6語法塊級作用域在ES6之前我們腦海裏應該只存在全局作用域和函數級作用域,沒有塊級作用域。那麽為什麽要引入塊級作用域呢?避免外層變量被覆蓋var str = "hello";function d() { console.log(str); if (false) { var str

一張圖讓Spring @Scheduled定時任務的fixedRate,fixedDelay,cron執行差異

https://blog.csdn.net/applebomb/article/details/52400154   看字面意思容易理解,但是任務執行長度超過週期會怎樣呢? 不多說,直接上圖: 測試程式碼: import java.text.DateFormat; imp

從原始碼入手,一文帶Spring AOP面向切面程式設計

基於這兩者的實現上,這次來探索下Spring的AOP原理。雖然AOP是基於Spring容器和動態代理,但不瞭解這兩者原理也絲毫不影響理解AOP的原理實現,因為大家起碼都會用。 AOP,Aspect Oriented Programming,面向切面程式設計。在很多

真的JavaScript計時器?

在今天之前我一直以為setTimeout這個函式是非同步的,無意中看到了一篇關於setTimeout的文章,發現自己以前的認識全是錯誤的,趕緊總結下。 先看一段程式碼: var start = new Date(); setTimeout(function(

一篇教spring bean工廠和aop

這篇文章為spring回顧總結的第二篇,本篇主要分為兩個部分,分別是spring的bean工廠的實現.spring的aop實現原理,這兩部分也是面試當中問的比較多的. spring的bean工廠的實現 spring的bean工廠的實現可以有以下三種方式 靜態工廠實現 public class

真的適合學習JAVA開發

JAVA為什麼有前途?     過去的十多年,JAVA基本每年都是全世界使用人數第一的語言。全世界數百萬的IT企業構建了龐大的JAVA生態圈,大量的軟體基於JAVA開發。JAVA也被譽為“計算機界的英語”。 JAVA的應用範圍涉及所有行業、絕大多數IT企業,形成了龐大

真的適合學習JAVA開發

                JAVA為什麼有前途?     過去的十多年,J

程式設計師們節日快樂!真的啥是1024

你真的懂啥是1024嗎? 今天就是一年一度的1024節了! package com.ocnyang.app; /** * 程式設計師們,1024快樂。 */ public class Hello1024 { public static final String PROGRAM

【轉】真的select Socket模型

你看到的這個文章來自於http://www.cnblogs.com/ayanmw 轉自:http://www.cppblog.c

真的 i++ 和 ++i

對於 ++i 和 i++,許多人可能都知道,不就是先加1再取值,和先取值再加1嘛。然而,真的是這樣嗎?請先看以下4道題,能全部答對可以忽略這篇文章。 **題目** ```java // 示例1 int i = 1; i = i++; System.out.println("i = " + i); //

終於搞Spring中Scope為Request和Session的Bean

之前只是很模糊的知道其意思,在request scope中,每個request建立一個新的bean,在session scope中,同一session中的bean都是一樣的 但是不知道怎麼用程式碼去驗證它 今天可找到驗證它的程式碼了 首先定義一個簡單的類 ```java import lombok.Ge

真的JAVA

java宏觀方面一、JAVA。要想成為JAVA(高級)工程師肯定要學習JAVA。一般的程序員或許只需知道一些JAVA的語法結構就可以應付了。但要成為JAVA(高級) 工程師,您要對JAVA做比較深入的研究。您應該多研究一下JDBC、IO包、Util包、Text包、JMS、EJB、RMI、線程。如果可能,希望您

#乾貨文:java多執行緒高階教程,這些

一、countdownLatch和cyclicbarrier(這兩個做多執行緒控制很好用,工作中會經常用到) countdownLatch:主執行緒阻塞,當多個執行緒countdown到0,主執行緒執行; cyclicbarrier:多個執行緒等待,當都處於等待

Spring Boot 新一代Spring Java應用 : 能感覺在使用 JavaEE 規範

Spring官方網站本身使用Spring框架開發,隨著功能以及業務邏輯的日益複雜,應用伴隨著大量的XML配置檔案以及複雜的Bean依賴關係。隨著Spring 3.0的釋出,Spring IO團隊逐漸開始擺脫XML配置檔案,並且在開發過程中大量使用“約定優先配置”(convention over config

成為一名JAVA程式設計師的必備知識!

每逢長假都會有很多程式設計師跳槽,十一、過年是跳槽黃金時刻,尤其是過年。過年的時候年終獎到手,沒有了多少牽掛,年終同學同事聚會比較多,溝通的就多,各種工作機會的訊息也相應會多,所以跳槽的機會也就會多。跳槽就必不可少的要經過面試,那麼作為一個Java程式設計師需要準備哪些面試

Spring Context 真的

今天介紹一下大家常見的一個單詞 context 應該怎麼去理解,正確的理解它有助於我們學習 spring 以及計算機系統中的其他

Spring解決迴圈依賴,真的

## 導讀 - 前幾天發表的文章[SpringBoot多資料來源動態切換](https://chenjiabing666.github.io/2020/03/12/SpringBoot%E6%95%B4%E5%90%88%E5%A4%9A%E6%95%B0%E6%8D%AE%E6%BA%90%EF%BC%8

大學生求職難,關卡在哪?真正

eight 聲明 道路 每年 .cn .com 求職 公司 技能 上大學、找工作、結婚、生子——原以為人生可以這樣按部就班地過下去。可誰知,既定軌跡才剛行進到第二步,就意外地卡了殼。現在,越來越多的大學畢業生找工作屢屢碰壁,“沒有經驗"成了他們被拒之門外的理由;更有