1. 程式人生 > >學妹問的Spring Bean常用配置,我用最通俗易懂的講解讓她學會了

學妹問的Spring Bean常用配置,我用最通俗易懂的講解讓她學會了

你好呀,我是沉默王二,一枚有趣的程式設計師,寫的文章一直充滿靈氣,力求清新脫俗。昨天跑去王府井的小米店訂購了一臺小米 10,說是一週之內能到貨,但我還是忍不住今天就想見到她。見我茶不思飯不想的,老婆就勸我說,與其在瞎想,還不如滾去寫你的文章。於是就有了今天這篇“Spring Bean 的常用配置”,通過我和三妹對話的形式。

教妹學 Java,沒見過這麼放肆的標題吧?“語不驚人死不休”,沒錯,本篇文章的標題就是這麼酷炫,不然你怎麼會點進來?

我有一個漂亮如花的妹妹(見上圖),她叫什麼呢?我想聰明的讀者能猜得出:沉默王三,沒錯,年方三六。父母正考慮讓她向我學習,做一名正兒八經的 Java 程式設計師。我期初是反對的,因為程式設計師這行業容易掉頭髮。但家命難為啊,與其反對,不如做點更積極的事情,比如說寫點有趣的文章教教她。

“二哥,Spring 基礎篇學完後,我有一種強烈的感覺,Spring 真的好強大,就如春風佛面一般,好像學下一篇。”

“哎呀,三妹,你這個比喻雖然有些牽強,但多少有些詩意。”

“好吧,讓我們開始今天的學習吧!”

01、Bean 的 Scope 配置

“二哥,據說 Bean 的 Scope 型別有好幾種,用於定義了 Bean 的生命週期和使用環境,你能給我具體說說嗎?”

“沒問題啊。”

1)singleton

也就是單例模式,如果把一個 Bean 的 Scope 定義為 singleton,意味著一個 Bean 在 Spring 容器中只會建立一次例項,對該例項的任何修改都會反映到它的引用上面。這也是 Scope 的預設配置項,可省略。

來新建一個 Writer 類,內容如下:

public class Writer {
    private String name;

    public Writer() {
    }

    // getter setter
}

再來新建一個 SingletonConfig 類,內容如下:

@Configuration
public class SingletonConfig {
    @Bean
    @Scope("singleton")
    public Writer getWriterSingleton() {
        return new Writer();
    }
}

@Configuration 註解表明當前類是一個配置類,相當於 Spring 配置的一個 xml 檔案。

@Bean 註解用在 getWriterSingleton() 方法上,表明當前方法返回一個 Bean 物件(Writer),然後將其交給 Spring 管理。

可以使用 Spring 定義的常量來代替字串 singleton:

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)

當然也可以完全省略,於是 SingletonConfig 瘦身了。

@Configuration
public class SingletonConfig {
    @Bean
    public Writer getWriterSingleton() {
        return new Writer();
    }
}

新建 SingletonMain 類,程式碼如下:

public class SingletonMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SingletonConfig.class);
        Writer writer1 = context.getBean(Writer.class);
        Writer writer2 = context.getBean(Writer.class);

        System.out.println(writer1);
        System.out.println(writer2);

        writer1.setName("沉默王二");
        System.out.println(writer2.getName());

        context.close();
    }
}

程式輸出的結果如下所示:

commonuse.singleton.Writer@19dc67c2
commonuse.singleton.Writer@19dc67c2
沉默王二

writer1 和 writer2 兩個物件的字串表示形式完全一樣,都是 commonuse.singleton.Writer@19dc67c2;另外,改變了 writer1 物件的 name,writer2 也跟著變了。

從結果中我們可以得出這樣的結論:Scope 為 singleton 的時候,儘管使用 getBean() 獲取了兩次 Writer 例項,但它們是同一個物件。只要更改它們其中任意一個物件的狀態,另外一個也會同時改變。

2)prototype

prototype 的英文詞義是複數的意思,它表示一個 Bean 會在 Spring 中建立多次例項,適合用於多執行緒的場景。

新建一個 PrototypeConfig 類,內容如下:

@Configuration
public class PrototypeConfig {
    @Bean
    @Scope("prototype")
    public Writer getWriterPrototype() {
        return new Writer();
    }
}

可以使用 Spring 定義的常量來代替字串 prototype:

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

新建 PrototypeMain 類,程式碼如下:

public class PrototypeMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrototypeConfig.class);
        Writer writer1 = context.getBean(Writer.class);
        Writer writer2 = context.getBean(Writer.class);

        System.out.println(writer1);
        System.out.println(writer2);

        writer1.setName("沉默王二");
        System.out.println(writer2.getName());

        context.close();
    }
}

程式輸出的結果如下所示:

commonuse.Writer@78a2da20
commonuse.Writer@dd3b207
null

writer1 和 writer2 兩個物件的字串表示形式完全不一樣,一個是 commonuse.Writer@78a2da20,另一個是 commonuse.Writer@dd3b207;另外,雖然 writer1 物件的 name 被改變為“沉默王二”,但 writer2 的 name 仍然為 null。

從結果中我們可以得出這樣的結論:Scope 為 prototype 的時候,每次呼叫 getBean() 都會返回一個新的例項,它們不是同一個物件。更改它們其中任意一個物件的狀態,另外一個並不會同時改變。

3)request、session、application、websocket

這 4 個作用域僅在 Web 應用程式的上下文中可用,在實踐中並不常用。request 用於為 HTTP 請求建立 Bean 例項,session 用於為 HTTP 會話建立 Bean 例項, application 用於為 ServletContext 建立 Bean 例項,而 websocket 用於為特定的 WebSocket 會話建立 Bean 例項。

02、Bean 的欄位注入

“二哥,據說 Spring 開發中經常涉及呼叫各種配置檔案,需要用到 @Value 註解,你能給我詳細說說嗎?”

“沒問題啊。”

1)注入普通字串

來新建一個 ValueConfig 類,內容如下:

@Configuration
public class ValueConfig {
    @Value("沉默王二")
    private String name;

    public void output() {
        System.out.println(name);
    }
}

@Value 註解用在成員變數 name 上,表明當前注入 name 的值為“沉默王二”。

來新建一個 ValueMain 類,內容如下:

public class ValueMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpELStringConfig.class);

        SpELStringConfig service = context.getBean(SpELStringConfig.class);
        service.output();

        context.close();
    }
}

程式輸出結果如下:

沉默王二

結果符合我們的預期。

2)注入 Spring 表示式

使用 @Value 注入普通字串的方式最為簡單,我們來升級一下,注入 Spring 表示式,先來個加法運算吧。

@Value("#{18 + 12}") // 30
private int add;

雙引號中需要用到 #{}。再來個關係運算和邏輯運算吧。

@Value("#{1 == 1}") // true
private boolean equal;

@Value("#{400 > 300 || 150 < 100}") // true
private boolean or;

覺得還不夠刺激,再來個三元運算吧。

@Value("#{2 > 1 ? '沉默是金' : '不再沉默'}") // "沉默是金"
private String ternary;

3)注入配置檔案

假如你覺得以上這些都不夠有意思,那來注入配置檔案吧。

在 resources 目錄下新建 value.properties 檔案,內容如下:

name=沉默王二
age=18

新建一個 ValuePropertiesConfig 類,內容如下:

@Configuration
@PropertySource("classpath:value.properties")
public class ValuePropertiesConfig {

    @Value("${name}")
    private String name;

    @Value("${age}")
    private int age;

    public void output() {
        System.out.println("姓名:" + name + " 年紀:" + age);
    }
}

@PropertySource 註解用於指定載入哪個配置檔案(value.properties),classpath: 表明從 src 或者 resources 目錄下找。

注意此時 @Value("") 的雙引號中為 $ 符號而非 # 符號,{} 中為配置檔案中的 key。

新建一個 ValuePropertiesMain 類,內容如下:

public class ValuePropertiesMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ValuePropertiesConfig.class);

        ValuePropertiesConfig service = context.getBean(ValuePropertiesConfig.class);
        service.output();

        context.close();
    }
}

程式執行結果如下:

姓名:³ÁĬÍõÈý 年紀:18

“糟糕,二哥!中文亂碼了!”

“不要怕,三妹,問題很容易解決。”

首先,檢視 properties 檔案的編碼方式。

如果不是 UTF-8 就改為 UTF-8。同時,確保修改編碼方式後的 properties 檔案中沒有中文亂碼。

然後,在 @PropertySource 註解中加入編碼格式。

@PropertySource(value = "classpath:value.properties",  encoding = "UTF-8")

再次執行程式後,亂碼就被風吹走了。

姓名:沉默王二 年紀:18

03、Bean 的初始化和銷燬

“二哥,據說在實際開發中,經常需要在 Bean 初始化和銷燬時加一些額外的操作,你能給我詳細說說怎麼實現嗎?”

“沒問題啊。”

1)init-method/destroy-method

新建一個 InitDestroyService 類,內容如下:

public class InitDestroyService {
    public InitDestroyService() {
        System.out.println("構造方法");
    }

    public void init() {
        System.out.println("初始化");
    }

    public void destroy {
        System.out.println("銷燬");
    }
}

InitDestroyService() 為構造方法,init() 為初始化方法,destroy() 為銷燬方法。

新建 InitDestroyConfig 類,內容如下:

@Configuration
public class InitDestroyConfig {
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public InitDestroyService initDestroyService() {
        return new InitDestroyService();
    }
}

@Bean 註解的 initMethod 用於指定 Bean 初始化的方法,destroyMethod 用於指定 Bean 銷燬時的方法。

新建 InitDestroyMain 類,內容如下:

public class InitDestroyMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(InitDestroyConfig.class);
        InitDestroyService service = context.getBean(InitDestroyService.class);
        System.out.println("準備關閉容器");
        context.close();
    }
}

程式執行結果如下:

構造方法
初始化
準備關閉容器
銷燬

也就是說,初始化方法在構造方法後執行,銷燬方法在容器關閉後執行。

2)@PostConstruct/@PreDestroy

新建一個 InitDestroyService 類,內容如下:

public class InitDestroyService {
    public InitDestroyService() {
        System.out.println("構造方法");
    }

    @PostConstruct
    public void init() {
        System.out.println("初始化");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("銷燬");
    }
}

@PostConstruct 註解的作用和 @Bean 註解中 init-method 作用相同,用於指定 Bean 初始化後執行的方法。

@PreDestroy 註解的作用和 @Bean 註解中 destroyMethod 作用相同,用於指定 Bean 被容器銷燬後執行的方法。

新建 InitDestroyConfig 類,內容如下:

@Configuration
public class InitDestroyConfig {
    @Bean
    public InitDestroyService initDestroyService() {
        return new InitDestroyService();
    }
}

@Bean 註解中不需要再指定 init-method 和 destroyMethod 引數了。

新建 InitDestroyMain 類,內容如下:

public class InitDestroyMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(InitDestroyConfig.class);
        InitDestroyService service = context.getBean(InitDestroyService.class);
        System.out.println("準備關閉容器");
        context.close();
    }
}

程式執行結果如下:

構造方法
初始化
準備關閉容器
銷燬

結果符合我們的預期。

04、為 Bean 配置不同的環境

“二哥,據說 Spring 開發中經常需要將 Bean 切換到不同的環境,比如說開發環境、測試環境、正式生產環境,你能給我具體說說怎麼實現的嗎?”

“沒問題啊。”

來考慮這樣一個常見的場景,我們需要為開發環境和正式生產環境配置不同的資料來源。

新建 Datasource 類,內容如下:

public class Datasource {
    private String dburl;

    public Datasource(String dburl) {
        this.dburl = dburl;
    }

    // getter/setter
}

dbname 用於指定不同環境下資料庫的連線地址。

新建 Config 類,內容如下:

@Configuration
public class Config {
    @Bean
    @Profile("dev")
    public Datasource devDatasource() {
        return new Datasource("開發環境");
    }

    @Bean
    @Profile("prod")
    public Datasource prodDatasource() {
        return new Datasource("正式生產環境");
    }
}

@Profile 註解用於標識不同環境下要例項化的 Bean。

新建 Main 類,內容如下:


            
           

相關推薦

Spring Bean常用配置通俗易懂講解學會

你好呀,我是沉默王二,一枚有趣的程式設計師,寫的文章一直充滿靈氣,力求清新脫俗。昨天跑去王府井的小米店訂購了一臺小米 10,說是一週之內能到貨,但我還是忍不住今天就想見到她。見我茶不思飯不想的,老婆就勸我說,與其在瞎想,還不如滾去寫你的文章。於是就有了今天這篇“Spring Bean 的常用配置”,通過我和三

【MVC】Spring MVC常用配置

solver errors 自動裝箱 property byte mco 驗證 c基礎 form表單 一、SpringMVC基礎入門,創建一個HelloWorld程序 1.首先,導入SpringMVC需要的jar包。 2.添加Web.xml配置文件中關於Spring

Spring Boot常用配置

resource intellij runtime 默認 per context none splay 文件的 概述     本文主要寫了下Spring Boot的一些常用配置。 Spring Boot基本配置     入口類:         Sprin

spring bean配置----applicationContext.xml

spring 配置檔案的根元素是<beans> ,<beans>中包含了多個<bean>子元素,每個<bean>元素定義一個Bean,並描述Bean如何被裝配到spring容器中。 bean元素常用屬性及其子元素如下

Spring Boot 常用配置以及自定義配置

原文地址:https://renguangli.com/articles/spring-boot-config Spring Boot 常用配置簡單介紹及使用 多環境配置 Spring Boot Profile 在 Spring Boot 中多環境配置檔名需要滿足 app

IntelliJ IDEA 常用配置應用、永久啟用

包含 1、最常用配置 2、應用 3、永久啟用 剛剛使用IntelliJ IDEA 編輯器的時候,會有很多設定,會方便以後的開發,磨刀不誤砍柴工。 比如:設定檔案字型大小,程式碼自動完成提示,版本管理,原生代碼歷史,自動匯入包,修改註釋,修改tab的顯示的數量和行數,開啟專案方式,等等一

Spring 表單對映到Bean的規則並實現簡化Spring表單提交

Spring中form表單對映到Bean的限止:     * 1,form表單中的欄位必須和Bean裡的欄位一樣,或比bean裡的欄位少     * 2,form表單中的name和Bean的欄位必須小寫   由於以上限止,本人研究有一下方法解決demo如下 <d

IDEA的幾個常用配置日常開發必備。

書寫 修改字體 一個 字體 快捷 右下角 reference 剛才 代碼 用了IDEA有很長時間了,身邊的同事朋友也都慢慢的開始都從Eclipse切換到IDEA了,其實無論是Eclipse還是IntelliJ IDEA都是開發工具而已,各自都有優點。但是剛從Eclipse切

Spring Bean常用擴充套件介面

一、前言     1、Spring框架運用了非常多的設計模式,從整體上看,它的設計嚴格遵循了OCP---開閉原則,即         【1】保證對修改關閉,即外部無法修改Spring整個運作的流程         【2】提供對擴充套件開放,即可以通過繼承、實現S

spring boot之spring mvc常用配置--攔截器配置(4)

2.攔截器配置 攔截器Interceptor實現對每一個請求處理前後進行相關的業務處理。類似於Servlet的Filter。 第一種方式:可以讓普通的bean實現HandlerInterceptor介面或者繼承HandlerInterceptorAdapter類來實現自定義

springboot中logback日誌常用配置包含日誌切割

新增依賴: <!--監控--> <dependency> <groupId>org.springframework.boot</groupId>

Spring Boot 國際化配置訊息化引數

spirn boot 國際化配置,訊息化引數 1. 新增資原始檔 messages_zh_CN.properties # 註冊登入 userid.is.null= 請輸入使用者名稱!

spring boot之spring mvc常用配置--路徑匹配引數設定(7)

路徑匹配引數設定 在spring mvc中,路徑引數帶".","."後面的值將會忽略。 http://localhost:8080/index.xx實際訪問的路徑是http://localhost:8

使用Spring整合Hibernate配置根據實體類自動建立表

<?xml version="1.0" encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instan

IdeaJ 常見插件安裝 常用配置常用快捷鍵

快捷鍵設置 set basic 常用配置 alt 常用快捷鍵 code 提示 key -- 系統是 Ubuntu 16.04 1, 插件: 2, 常見的設置:   [1] 代碼提示的修改: File --> settings --> Keyma

Spring Bean相關配置

bean 配置 ava 名稱 glob init lob globals 唯一約束 Bean相關配置 1.名稱與標識 id 使用了約束中的唯一約束。裏面不能出現特殊字符的 name 沒有使用約束中的唯一約束。裏面可以出現特殊字符。 設置對象的生命周期方法 init-met

單頁面跳轉添加返回和跳轉動畫(仿app) 只對單頁面和跳轉有用的是angualr有不會的可以私信

hist page func margin consola color -s tar pla p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Consolas; color: #596972 } p.p2 { mar

nginx安裝默認主機配置Nginx戶認證Nginx域名重定向

nginx安裝默認主機配置Nginxnginx安裝cd /usr/local/srcwget http://220.112.193.202/files/302100000569FBE9/nginx.org/download/nginx-1.12.2.tar.gz解壓到/usr/local/nginx./con

OpenLDAP客戶端配置實現戶認證(原創)

pen img sss fuse sys src file 由於 onf 1.工作過程 OpenLDAP服務分為客戶端和服務端兩個部分,服務端的配置過程這裏不再贅述。當服務端配置結束後,在服務端的ldap數據庫中,應存放著用戶的信息,客戶端通過安裝nss-p

緊急整理 20 道 Spring Boot 面試題經常拿來面試別人!

面試了一些人,簡歷上都說自己熟悉 Spring Boot, 或者說正在學習 Spring Boot,一問他們時,都只停留在簡單的使用階段,很多東西都不清楚,也讓我對面試者大失所望。 下面,我給大家總結下有哪些 Spring Boot 的面試題,這是我經常拿來問面試者的,希望對你有幫助。