成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

@Configuration 注解的 Full 模式和 Lite 模式!

開發 前端
如果設置了 proxyBeanMethods 屬性為 false,那么也就是 Lite 模式了,其實我們從屬性名稱上也能看出來端倪:是否代理 @Bean 注解標記的方法。

@Configuration 注解相信各位小伙伴經常會用到,但是大家知道嗎,這個注解有兩種不同的模式,一種叫做 Full 模式,另外一種則叫做 Lite 模式。

準確來說,Full 模式和 Lite 模式其實 Spring 容器在處理 Bean 時的兩種不同行為。

這兩種不同的模式在使用時候的表現完全不同,今天松哥就來和各位小伙伴捋一捋這兩種模式。

1. 概念梳理

首先我們先來看一下 Spring 官方文檔中對 Full 模式和 Lite 模式的一個介紹:

圖片圖片

截圖來自:https://docs.spring.io/spring-framework/reference/core/beans/java/basic-concepts.html

這個文檔主要講了這樣幾件事情:

  1. 我們可以通過在一個方法上添加 @Bean 注解,進而將該方法的返回值暴露給 Spring 容器,在這種場景下,@Bean 注解實際上就是一種通用的工廠方法機制。
  2. 當一個添加了 @Bean 注解的方法位于一個沒有添加 @Configuration 注解的類里邊時,那么這個添加了 @Bean 注解的方法在處理時就會按照 Lite 模式來處理。
  3. 當一個 Bean 被聲明在添加了 @Component 注解的類中,那么會按照 Lite 模式來處理。
  4. 當一個 Bean 被聲明在一個普通的類中時(plain old class),按照 Lite 模式來處理(這一點感覺和第二點差不多)。
  5. 在 Lite 模式下,@Bean 注解標記的方法最終不會被 CGLIB 進行代理,就是一個普通的工廠方法,因此,在 @Bean 標記的方法中,不能調用其他 @Bean 注解標記的方法,如果有需要,可以通過方法參數注入自己所需要的 Bean。
  6. 由于 Lite 模式下并不會使用 CGLIB,因此 @Bean 標記的方法可以是 final 類型的。
  7. 在大多數場景下,我們在一個 @Configuration 注解標記的類中,使用 @Bean 注解向 Spring 容器注冊一個 Bean,都是 Full 模式。

官網文檔的介紹還是有些抽象,接下來松哥通過具體的案例來和大家演示 Full 模式和 Lite 模式的差別。

2. Full 模式

先看 Full 模式,中文也可以稱之為 完整 模式,我們平時使用時,在一個配置類上添加 @Configuration 注解,且不添加任何額外屬性,這就是 Full 模式了。

Full 模式最大的特點是會給配置類通過 CGLIB 生成一個代理,所有被 @Bean 注解標記的方法將來都是通過代理方法進行調用。

假設我有如下配置類:

@Configuration
public class JavaConfig {

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

現在,我們去 Spring 容器獲取這個配置類:

public class JavaDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
        JavaConfig config = ctx.getBean(JavaConfig.class);
        System.out.println("config.getClass() = " + config.getClass());
    }
}

打印結果如下:

圖片圖片

大家看到,最終從 Spring 容器中拿到的 JavaConfig 實例并不是原始的 JavaConfig 對象,而是一個被代理的 JavaConfig 對象。

為什么要代理呢?肯定是為了實現某些功能。

大家看下面這個案例:

@Configuration
public class JavaConfig {

    @Bean
    User user() {
        User user = new User();
        user.setDog(dog());
        return user;
    }
    
    @Bean
    Dog dog() {
        return new Dog();
    }
}

在 Full 模式下,在 user() 方法中調用 dog() 方法的時候,調用的是一個代理對象的 dog 方法,在這個代理對象的 dog 方法中,會首先去檢查 Spring 容器中是否存在 Dog 對象,如果存在,則直接使用 Spring 容器中的 dog 對象,就不會真正去執行 dog 方法而獲取到一個新的 dog 對象了,如果 Spring 容器中不存在 dog 對象,才會創建新的 dog 對象出來。

一言以蔽之,在 Full 模式下,user 中的 dog 對象和 dog 方法注冊到 Spring 容器的 dog 對象是同一個。

在 Full 模式下,由于要給當前類生成代理,然后去代理 @Bean 注解標記的方法,因此,這些 @Bean 注解標記的方法不能是 final 或者 private 類型的,因為 final 或者 private 類型的方法無法被重寫,也就沒法生成代理對象,如果添加了 final 或者 private 修飾符,那么會拋出如下異常:

圖片圖片

3. Lite 模式

再來看 Lite 模式,這種模式可以認為是一種精簡模式。

怎么開啟呢?我們可以去除配置類上的 @Configuration 注解,或者去除之后添加 @Component 注解,又或者使用 @ComponentScan、@ImportResource、@Import 等注解標記類,那么最終都是 Lite 模式:

@Component
public class JavaConfig {

    @Bean
    final User user() {
        User user = new User();
        user.setDog(dog());
        return user;
    }

    @Bean
    Dog dog() {
        return new Dog();
    }
}

此時就是 Lite 模式,現在我們去 Spring 容器中獲取這個配置類:

public class JavaDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
        JavaConfig config = ctx.getBean(JavaConfig.class);
        System.out.println("config.getClass() = " + config.getClass());
    }
}

最終打印結果如下:

圖片圖片

大家看到,我們從 Spring 容器中拿到的就是原始的對象,而不是一個被代理過的對象。因此:

  1. 由于 @Bean 注解標記的方法沒有被代理,因此,該方法可以是 final 也可以是 private,運行時都不會報錯。
  2. 由于 @Bean 方法沒有被代理,因此在 user 方法中調用 dog 方法的時候,就直接調用了,這就導致 user 中的 dog 和最終 dog 方法注冊到 Spring 容器中的 dog 不是同一個。

針對第二點,如果想要確保 user 中的 dog 和 Spring 容器中的 dog 是同一個,那么可以通過參數將所需要的對象注入進來,類似下面這樣:

@Component
public class JavaConfig {

    @Bean
    final User user(Dog dog) {
        User user = new User();
        user.setDog(dog);
        return user;
    }

    @Bean
    Dog dog() {
        return new Dog();
    }
}

當 Spring 容器調用 user 方法初始化 User 對象時,發現該方法還有參數,因此會去容器中查找這個參數,找到了直接使用。

另外,我們也可以在類上添加 @Configuration 注解,但是通過修改屬性值來啟用 Lite 模式:

@Configuration(proxyBeanMethods = false)
public class JavaConfig {

    @Bean
    final User user(Dog dog) {
        User user = new User();
        user.setDog(dog);
        return user;
    }

    @Bean
    Dog dog() {
        return new Dog();
    }
}

如果設置了 proxyBeanMethods 屬性為 false,那么也就是 Lite 模式了,其實我們從屬性名稱上也能看出來端倪:是否代理 @Bean 注解標記的方法。

4. 小結

總結一下:

  1. Lite 模式下,配置類中的方法就是普通方法,可以是 final 類型,也可以是 private。
  2. Lite 模式下,不需要通過 CGLIB 生成動態代理類,所以啟動速度會快一些。
  3. Lite 模式下,一個 @Bean 方法調用另外一個 @Bean 方法,會導致同一個 Bean 被初始化兩次。
  4. Full 模式下,會給配置類生成一個動態代理類,配置類中的所有方法都將被動態代理,因此配置類中的方法不能是 final 或者 private 的。
  5. Full 模式下,一個 @Bean 方法調用另外一個 @Bean 方法,動態代理方法會先去容器中檢查是否存在該 Bean,如果存在,則直接使用容器中的 Bean,否則才會去創建新的對象。

日常開發中,我們使用較多的是 Full 模式。

責任編輯:武曉燕 來源: 江南一點雨
相關推薦

2023-05-23 22:06:47

云平臺

2010-09-27 15:17:48

JVM client模式server模式

2011-08-01 10:35:26

數據庫外模式模式

2023-10-25 08:17:06

Lite模式代理類

2021-04-19 21:25:48

設計模式到元

2024-04-12 12:10:18

Python設計模式開發

2023-10-30 18:59:38

REST API開發

2022-04-15 08:30:00

Lombok@Builde構建器

2010-09-27 16:07:06

JVM Server模Client模式

2024-06-04 13:11:52

Python行為設計模式開發

2012-02-10 09:55:26

2012-08-30 09:07:33

設計模式

2015-10-22 13:10:43

CDN

2010-10-28 11:36:16

Oracle用戶

2022-10-27 11:46:48

ConfiguratValuespring

2022-08-29 15:26:58

MySQLSQL模式

2021-03-06 22:50:58

設計模式抽象

2025-01-09 11:15:47

2009-12-28 10:47:17

MPLS技術

2013-11-08 14:57:37

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲欧美激情精品一区二区 | 精品一区二区三区四区外站 | 人人精品 | 欧美久久国产 | 亚洲中国字幕 | 亚洲人成人一区二区在线观看 | 亚洲精品一区二三区不卡 | 久久久精品国产 | 91精品国产91久久久久青草 | 午夜爱爱毛片xxxx视频免费看 | 在线亚洲人成电影网站色www | 中国一级特黄毛片大片 | 一区二区三区四区av | 国产精品日韩欧美一区二区三区 | 久热国产精品视频 | 日韩欧美视频 | 国产一级片久久久 | 日韩电影在线一区 | 黄色国产视频 | 久久这里只有精品首页 | 91看片免费| 在线第一页 | 国产不卡在线 | 欧美成人a∨高清免费观看 老司机午夜性大片 | 亚洲 一区 | 色婷婷狠狠 | 国产人久久人人人人爽 | 国产精品视频偷伦精品视频 | 亚洲天堂一区 | 亚洲高清av | 午夜成人在线视频 | 精品一区国产 | 黄色三级免费 | 久久久久久国产精品免费免费 | 午夜影晥 | 盗摄精品av一区二区三区 | 欧美一区二区免费电影 | 日韩一区二区在线视频 | 99精品久久久 | 亚洲一区二区在线播放 | 国产欧美久久精品 |