在〈使用 Spring DI〉中,初步使用了 Spring DI 的 JavaConfig 以及自動綁定功能,不過,AppConfig
中的 JDBC URL、名稱、密碼等是寫死的,雖然 AppConfig
應看成是設定檔的角色,然而,畢竟它是個 .java,會編譯為 .class,某些設定若能不寫死,還是比較方便更改設定的。
Spring 中,可以使用 @Value
來為字串注入值,可以將 AppConfig
修改為:
package cc.openhome;
import javax.sql.DataSource;
import org.h2.jdbcx.JdbcDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@ComponentScan
@PropertySource("classpath:jdbc.properties")
public class AppConfig {
@Value("jdbc:h2:tcp://localhost/c:/workspace/SpringDI2/gossip")
private String jdbcUrl;
@Value("caterpillar")
private String user;
@Value("12345678")
private String password;
@Bean
public DataSource getDataSource() {
JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL(jdbcUrl);
dataSource.setUser(user);
dataSource.setPassword(password);
return dataSource;
}
}
呃?這算什麼?然而是在 .java 中寫死了值啊!〈在 DI 之前〉中載入屬性檔案的部份呢?這可以透過 PropertySourcesPlaceholderConfigurer
實例讀取,並提供給 Spring 注入指定的屬性之用:
package cc.openhome;
import javax.sql.DataSource;
import org.h2.jdbcx.JdbcDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@ComponentScan
@PropertySource("classpath:jdbc.properties")
public class AppConfig {
@Value("${cc.openhome.jdbcUrl}")
private String jdbcUrl;
@Value("${cc.openhome.user}")
private String user;
@Value("${cc.openhome.password}")
private String password;
@Bean
public DataSource getDataSource() {
JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL(jdbcUrl);
dataSource.setUser(user);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public static PropertySourcesPlaceholderConfigurer
propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
PropertySourcesPlaceholderConfigurer
實例是 Spring 本身需要的 Bean,通常你不需要在應用程式中直接取用它,也就是說,設定檔中除了設定應用程式需要的 Bean 之外,也會用來設定 Spring 本身用到的資源。
留意一下 static
,那是必要的,這是因為 PropertySourcesPlaceholderConfigurer
實作了 BeanFactoryPostProcessor
介面,BeanFactory
(AnnotationConfigApplicationContext
實現的介面之一)會在載入 Bean 定義檔之後,還沒生成 Bean 實例之前,執行 BeanFactoryPostProcessor
定義的 postProcessBeanFactory
方法。
如果使用 XML 方式定義 PropertySourcesPlaceholderConfigurer,其實是不用太在意這個過程,因為撰寫設定方式,基本上與其他 Bean 沒有差異。
然而,使用 JavaConfig 的方式設定時,這就意謂著 @Configuration
標註的類別在載入之後,生成實例之前,就必須能取得 PropertySourcesPlaceholderConfigurer
實例,因而 Spring 在這部份是透過 static
方法來解決。
PropertySourcesPlaceholderConfigurer
要讀取的設定檔來源,可以透過 @PropertySource
來指定,在上例中,@PropertySource("classpath:jdbc.properties")
表示,從類別路徑讀取 jdbc.properties:
cc.openhome.jdbcUrl=jdbc:h2:tcp://localhost/c:/workspace/SpringDI2/gossip
cc.openhome.user=caterpillar
cc.openhome.password=12345678
而在 @Value
的部份,值的設定使用了 ${...}
的 PlaceHolder 形式,如此一來,就可以將 .properties 中對應的值注入。
PlaceHolder 形式也可以設定預設值,例如 @Value("${cc.openhome.user:caterpillar}")
的話,在沒有對應的 cc.openhome.user 時,就會使用 "caterpillar"
這個值。
你可以在 SpringDI2 找到以上的範例專案。