1. 程式人生 > >Spring入門(九):執行時值注入

Spring入門(九):執行時值注入

Spring提供了2種方式在執行時注入值:

  1. 屬性佔位符(Property placeholder)
  2. Spring表示式語言(SpEL)

1. 屬性佔位符

1.1 注入外部的值

1.1.1 使用Environment

一般情況下,我們會將一些值放到配置檔案中,等程式執行時再把值注入到一些欄位上。

假如,我們有一個test.properties配置檔案,內容如下:

book.author=wangyunfei
book.name=spring boot
author.age=30

現在我們希望在程式執行時,把這個值分別賦值給欄位bookAuthor和bookName,那麼該如何實現呢?

首先,新建配置類ExpressiveConfig如下:

package chapter03.el;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

@Configuration
@ComponentScan
@PropertySource("classpath:chapter03/el/test.properties")
public class ExpressiveConfig {
    @Autowired
    private Environment environment;

    public void outputResource() {
        System.out.println("book.name:" + environment.getProperty("book.name"));
        System.out.println("book.author:" + environment.getProperty("book.author"));
    }
}

這裡我們使用@PropertySource註解引用了test.properties配置檔案,這個檔案的位置位於chapter03.el包下。

這個屬性檔案會載入到Spring的Environment中,然後我們就可以呼叫getProperty()方法獲取到屬性值。

新建Main類,在其main()方法中新增如下測試程式碼:

package chapter03.el;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

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

        ExpressiveConfig expressiveConfig = context.getBean(ExpressiveConfig.class);

        expressiveConfig.outputResource();

        context.close();
    }
}

執行程式碼,發現丟擲java.io.FileNotFoundException異常,如下所示:

從報錯資訊可以看出, 這是提示找不到chapter03/el/test.properties這個檔案,這是為什麼呢?

帶著這個疑問,我們看下target目錄下編譯後的程式碼,如下所示:

從圖中可以看出,我們新建的test.properties和test.txt檔案並沒有被編譯到target目錄下,所以才會丟擲異常。

這是因為,我們新建檔案的位置放在chapter03.el包下,而IDEA預設是不會把這些檔案自動複製到target目錄下的,但我們可以在pom.xml中新增如下配置來解決該問題:

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.txt</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
    </resources>
</build>

這裡我們指定了txt和properties檔案,如果需要,可以繼續新增<include>標籤指定xml等檔案。

再次執行測試程式碼,輸出日誌如下所示:

book.name:spring boot

book.author:wangyunfei

此時target目錄下已經包含了我們新建的2個檔案:

如果指定的屬性值不存在,getProperty()會返回null,如下所示:

String workCity = environment.getProperty("author.workcity");
System.out.println("author.workcity:" + workCity);

輸出結果:

author.workcity:null

getProperty()還提供了1個過載,當指定的屬性值不存在時,可以指定預設值:

String workCity = environment.getProperty("author.workcity", "上海");
System.out.println("author.workcity:" + workCity);

輸出結果:

author.workcity:上海

如果希望屬性值必須存在,可以使用getRequiredProperty()方法,當屬性值不存在時,會丟擲java.lang.IllegalStateException異常:

String workCity = environment.getRequiredProperty("author.workcity");
System.out.println("author.workcity:" + workCity);

getProperty()還提供了1個過載,可以指定返回值的型別,比如我們想返回Integer型別:

Integer authorAge = environment.getProperty("author.age", Integer.class);
System.out.println("author.age:" + authorAge);

輸出結果:

author.age:30

getProperty()還提供了1個過載,當指定的屬性值不存在時,不僅可以指定預設值,還可以指定返回值型別:

boolean isMan = environment.getProperty("author.isMan", Boolean.class, true);
System.out.println("author.isMan:" + isMan);

輸出結果:

author.isMan:true

1.1.2 使用屬性佔位符

除了使用Environment獲取外部的屬性值,我們還可以使用屬性佔位符來獲取。

在Spring裝配中,佔位符的形式為使用“${......}”包裝的屬性名稱。

新建Book類如下:

package chapter03.el;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Book {
    @Value("${book.name}")
    private String bookName;

    @Value("${book.author}")
    private String bookAuthor;

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookAuthor() {
        return bookAuthor;
    }

    public void setBookAuthor(String bookAuthor) {
        this.bookAuthor = bookAuthor;
    }
}

可以發現,我們在欄位上添加了@Value註解,引數傳的值就是屬性佔位符,用來獲取屬性檔案中指定的屬性值。

然後,在ExpressiveConfig配置類中新增如下程式碼:

@Autowired
private Book book;

public void outputResource() {
     System.out.println("book.name:" + book.getBookName());
     System.out.println("book.author:" + book.getBookAuthor());
}

輸出結果:

book.name:spring boot

book.author:wangyunfei

2. Spring表示式語言

Spring表示式語言(Spring Expression Language,SpEL)是一種非常靈活的表示式語言,能夠以一種強大和簡潔的方式將值裝配到bean屬性或者構造器引數中,在這個過程中所使用的的表示式會在執行時計算值。

SpEL表示式要放到“#{......}”之中,而之前講到的屬性佔位符是放到“${......}”之中。

接下來,我們分場景來看下Spring表示式語言的使用方法。

2.1 引用系統屬性值

在ExpressiveConfig中新增如下程式碼:

@Value("#{systemProperties['os.name']}")
private String osName;

public void outputResource() {
    System.out.println("os.name:" + osName);
}

輸出結果:

os.name:Windows 7

2.2 引用bean的屬性和方法

首先,新建一個類DemoService如下所示:

package chapter03.el;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class DemoService {
    @Value("DemoService類的another屬性")
    private String another;

    public String getAnother() {
        return another;
    }

    public void setAnother(String another) {
        this.another = another;
    }
}

然後,在ExpressiveConfig中新增如下程式碼:

@Value("#{demoService.another}")
private String fromAnother;

public void outputResource() {
    System.out.println("demoService.another:" + fromAnother);
}

表示式中的demoService為DemoService bean的ID,another是它的屬性。

輸出結果:

demoService.another:DemoService類的another屬性

表示式也可以修改為呼叫bean的方法:

@Value("#{demoService.getAnother()}")
private String fromAnother;

輸出結果不變,只是從呼叫屬性變成了呼叫方法。

呼叫完方法,可以對方法的返回值繼續呼叫其它方法,比如toUpperCase():

@Value("#{demoService.getAnother()?.toUpperCase()}")
private String fromAnother;

之所以使用"?."運算子,是為了避免當demoService.getAnother()返回null時,程式碼出現NullPointerException。

此時的輸出結果為:

demoService.another:DEMOSERVICE類的ANOTHER屬性

2.3 在表示式中使用型別

使用表示式生成1個隨機數:

@Value("#{T(java.lang.Math).random()}")
private double randomNumber;

public void outputResource() {
    System.out.println("randomNumber:" + randomNumber);
}

這裡我們使用T()引用了java.lang.Math類,然後呼叫了它的靜態方法random()。

輸出結果:

randomNumber:0.6801944394506442

2.4 使用運算子

上面的例子中,生成隨機數後,我們還可以使用乘法運算子,如下所示:

@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomNumber;

我們也可以在表示式中使用“+”運算子拼接字串,如下所示:

@Value("#{book.getBookName() + ' write by ' + book.getBookAuthor()}")
private String bookDescr;

public void outputResource() {
    System.out.println("bookDescr:" + bookDescr);
}

其中book為Book bean的ID,輸出結果如下所示:

bookDescr:spring boot write by wangyunfei

也可以在表示式中使用三元運算子:

@Value("#{systemProperties['os.name'] == 'Windows 7'?'Windows':'Linux'}")
private String osType;

public void outputResource() {
    System.out.println("osType:" + osType);
}

因為我的電腦系統是Windows 7,所以輸出結果如下所示:

osType:Windows

SpEL還支援很多的運算子,這裡只是列舉了幾個常用的例子,有興趣的同學可以自己深入研究下。

3. 原始碼及參考

原始碼地址:https://github.com/zwwhnly/spring-action.git,歡迎下載。

Craig Walls 《Spring實戰(第4版)》

汪雲飛《Java EE開發的顛覆者:Spring Boot實戰》

IDEA maven專案src原始碼下的資原始檔不自動複製到classes資料夾的解決方法

4. 最後

打個小廣告,歡迎掃碼關注微信公眾號:「申城異鄉人」,定期分享Java技術乾貨,讓我們一起進步。

相關推薦

Spring入門()執行時值注入

Spring提供了2種方式在執行時注入值: 屬性佔位符(Property placeholder) Spring表示式語言(SpEL) 1. 屬性佔位符 1.1 注入外部的值 1.1.1 使用Environment 一般情況下,我們會將一些值放到配置檔案中,等程式執行時再把值注入到一些欄位上。 假如,我們

Spring入門(一)Spring注入

概念 Spring注入是指在啟動Spring容器載入bean配置的時候,完成對變數的賦值行為 常用的兩種注入方式 設值注入 構造注入 設值注入 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns

spring入門框架整體簡介

mil object web開發 spa tor 對象 j2ee 就是 cor 1:spring的基本框架主要包含六大模塊:DAO、ORM、AOP、JEE、WEB、CORE   DAO:(Data Access Object) 數據訪問對象,是一個面向對象的數據庫接口。  

網絡編程懶人入門()通俗講解,有了IP地址,為何還要用MAC地址?

介紹 新手入門 未來 高速 時也 http協議 低延時 服務器 mina2 1、前言 標題雖然是為了解釋有了 IP 地址,為什麽還要用 MAC 地址,但是本文的重點在於理解為什麽要有 IP 這樣的東西。本文對讀者的定位是知道 MAC 地址是什麽,IP 地址是什麽。 (本文同

網路程式設計懶人入門()通俗講解,有了IP地址,為何還要用MAC地址?

1、前言 標題雖然是為了解釋有了 IP 地址,為什麼還要用 MAC 地址,但是本文的重點在於理解為什麼要有 IP 這樣的東西。本文對讀者的定位是知道 MAC 地址是什麼,IP 地址是什麼。 (本文同步釋出於:http://www.52im.net/thread-2067-1-1.html)

SPRING-入門(二)beans注入三種

一.spring IOC 在學習spring時,剛開始的時候,弄清楚,spring的ioc,控制反轉機制,將普通的Java物件(POJO),進行管理例項化,不再像以前一樣自己直接new出來了,而是由spring容器直接建立並進行管理。POJO之間的依賴關係也有s

Python並行程式設計()執行緒通訊queue

1、基本概念       當執行緒之間要共享資源或資料的時候,可能變的非常複雜。Python的threading模組提供了很多同步原語,包括訊號量,條件變數,事件和鎖。如果可以使用這些原語的話,應該優先考慮使用這些,而不是使用queue模組。佇列操作起來更容易,也使多執行緒程式設計更安全,因為佇列可以將資源的

Spring入門知識 ———— Spring_IOC屬性常用注入方式

一、引言 如何在IOC容器中配置Bean,這個是每個小夥伴得掌握的。在之前HelloWorld也有接觸過,那麼本章來介紹一下IOC常用的注入方式。一般來說常用的屬性注入、構造器注入的方式,本章會通過一

Spring入門學習(Bean的注入) 第一節

Spring學習 第一節 開始使用 Maven新增Spring依賴 使用XML配置檔案通過屬性注入Bean 通過構造方法來配置Bean的屬性 Bean的引用 小結 開始使用 Maven新增

筆記執行緒間的通訊(pthread_create()和pthread_self())

linux高階程式設計之執行緒間的通訊:(pthread_create()、pthread_self()) 1.執行緒概念     執行緒包含了表示程序內執行環境必須得資訊,其中包括程序中標識執行緒

JAX-RS入門執行

在上一節的裝備部分,列舉了必須的jar(在tomcat中執行)和可選的jar(作為一個獨立的應用程式執行)。這一節將分別介紹如何做為一個獨立的應用程式執行和如何在tomcat裡執行。 Tomcat(或者其他Web容器)中執行 要在tomcat之類的容器裡執行,首先需要定義一個Application類:

Spring入門(二)自動化裝配bean

pep 自動化 tdi req ngs mcr 完成 injection 實現類 Spring從兩個角度來實現自動化裝配: 組件掃描(component scanning):Spring會自動發現應用上下文中需要創建的bean。 自動裝配(autowiring):Spri

Spring入門(四)使用Maven管理Spring專案

讓我們先回顧下本系列的前3篇部落格: Spring入門(一):建立Spring專案 Spring入門(二):自動化裝配bean Spring入門(三):通過JavaConfig裝配bean 1.為什麼要使用Maven? 之前我們新建的專案,專案所要依賴的第三方jar包都在專案的類路徑下(通常為lib目錄)

Spring入門(五)Spring Bean Scope講解

1. 前情回顧 Spring入門(一):建立Spring專案 Spring入門(二):自動化裝配bean Spring入門(三):通過JavaConfig裝配bean Spring入門(四):使用Maven管理Spring專案 2. 什麼是Bean的Scope? Scope描述的是Spring容器是如何新

Spring Boot2()整合Jpa的基本使用

一、前言 今天早上看到一篇微信文章,說的是國內普遍用的Mybatis,而國外確普遍用的是Jpa。我之前也看了jpa,發現入門相當容易。jpa對於簡單的CRUD支援非常好,開發效率也會比Mybatis高出不少,因為JpaRepository會根據你定製的實體類,繼承了JpaRepository會有一套完整的封裝

Spring入門(六)條件化的bean

1. 概念 預設情況下,Spring中定義的bean在應用程式啟動時會全部裝配,不管當前執行的是哪個環境(Dev,QA或者Prod),也不管當前執行的是什麼系統(Windows或者Linux),但有些使用場景下,我們可能需要條件化的裝配某些bean,即當滿足某一條件時,裝配某些bean,當不滿足某一條件時,就

Spring入門(七)Spring Profile使用講解

1. 使用場景 在日常的開發工作中,我們經常需要將程式部署到不同的環境,比如Dev開發環境,QA測試環境,Prod生產環境,這些環境下的一些配置肯定是不一樣的,比如資料庫配置,Redis配置,RabbitMQ配置。 如果每次切換髮布環境,都需要修改配置重新構建的話,那對程式設計師來說將是噩夢,針對這種場景,S

Spring入門(八)自動裝配的歧義性

1. 什麼是自動裝配的歧義性? 在Spring中,裝配bean有以下3種方式: 自動裝配 Java配置 xml配置 在這3種方式中,自動裝配為我們帶來了很大的便利,大大的降低了我們需要手動裝配bean的程式碼量。 不過,自動裝配也不是萬能的,因為僅有一個bean匹配條件時,Spring才能實現自動裝配,如

Spring入門(十)Spring AOP使用講解

1. 什麼是AOP? AOP是Aspect Oriented Programming的縮寫,意思是:面向切面程式設計,它是通過預編譯方式和執行期動態代理實現程式功能的統一維護的一種技術。 可以認為AOP是對OOP(Object Oriented Programming 面向物件程式設計)的補充,主要使用在日誌

Spring入門(十三)Spring MVC常用註解講解

在使用Spring MVC開發Web應用程式時,控制器Controller的開發非常重要,雖然說檢視(JSP或者是Thymeleaf)也很重要,因為它才是直接呈現給使用者的,不過由於現在前端越來越重要,很多公司都開始採用前後端分離的開發模式,所以我們暫時可以將精力放在開發控制器上。 使用Spring MVC開