三、自定義配置

在向應用程序加入Spring Boot時,有個名為spring-boot-autoconfigure的JAR文件,其中包含很多的配置類。所有的配置如此的與眾不同,原因是它們利用了Spring的條件化配置。條件化配置允許配置存在于應用程序中,但在滿足某些特定條件之前都忽略這個配置。
舉個例子:

@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
    ...
}

以上是Spring Boot自動配置里的DataSourceAutoConfiguration的一個片段。DataSourceAutoConfiguration添加了@Configuration注解,表明這是一個配置類。最重要的是該類添加了@ConditionalOnClass注解,要求Classpath里必須要有DataSource和EmbeddedDatabaseType。如果他們不存在,條件就不成立,DataSourceAutoConfiguration提供的配置就會被忽略掉。

自動配置中使用的條件化注解:

  • @ConditionalOnBean: 配置了某個特定Bean
  • @ConditionalOnMissingBean: 沒有配置特定的Bean
  • @ConditionalOnClass: Classpath里有指定的類
  • @ConditionalOnMissingClass: Classpath里缺少指定的類
  • @ConditionalOnExpression: 給定的SpEL表達式計算結果為true
  • @ConditionalOnJava :Java的版本匹配特定值或者一個范圍值
  • @ConditionalOnJndi: 參數(shù)中給定的JNDI位置必須存在一個,如果沒有參數(shù),則需要JNDI InitialContext
  • @ConditionalOnProperty: 指定的配置屬性要有一個明確的值
  • @ConditionalOnResource: Classpath里有指定的資源
  • @ConditionalOnWebApplication: 這是一個Web應用程序
  • @ConditionalOnNotWebApplication: 這不是一個Web應用程序

1.覆蓋Spring Boot 的自動配置

我們以Spring Security來舉例。想要使用Spring Security,首先在pom.xml添加如下依賴:

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
  </dependency>

添加完依賴后,重構項目,此時該項目就可以運行。但訪問url地址時,它會提示你登錄。沒錯,此時只是用的Spring Security默認的配置,默認的配置可能滿足不了我們的需求,那么我們可以顯式地覆蓋Spring Security的自動配置。


默認的登錄頁面.png

覆蓋自動配置的顯示安全配置:

package com.jasonper.readinglist;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private ReaderRepository readerRepository;

    /**
     * 此configure方法設置了一個自定義的userDetailsService,這個服務可以是任意實現(xiàn)了userDetailsService的類,用于查找指定用戶名的用戶。
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(username -> readerRepository.findOne(username));
    }

    /**
     * 此configure方法指明:
     *      "/"的請求只有經過身份認證且具有READER角色的用戶采納訪問,其他的所有請求路徑向所有的用戶開放了訪問權限。
     *      這里還指定了登錄頁面和登錄失敗頁面
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").access("hasRole('READER')")
                .antMatchers("/**").permitAll()
                .and()
                .formLogin()
                .loginPage("/login")
                .failureUrl("/login?error=true");
    }
}

上面的例子足以演示如何覆蓋Spring Boot提供的安全自動配置。想要覆蓋Spring Boot的自動配置,我們所要做的僅僅是編寫一個顯示的java配置而已。

2.通過屬性文件外置配置

Spring Boot應用程序有多種設置途徑,包括如下幾處:
(1)命令行參數(shù)
(2)java:comp/env里的JNDI(Java Naming and Directory Interface)
(3)JVM系統(tǒng)屬性
(4)操作系統(tǒng)環(huán)境變量
(5)隨機生成的帶random.*前綴的屬性
(6)應用程序以外的application.properties或者application.yml文件
(7)打包在應用程序內的application.properties或者application.yml文件
(8)通過@PropertySource標注的屬性源
(9)默認屬性

Tips:上列表按照優(yōu)先級排序。
application.properties和application.yml文件能放在以下四個位置:

  • 外置,在相對于應用程序運行目錄的/config子目錄里
  • 外置,在應用程序運行的目錄里
  • 內置,在config包內
  • 內置,在Classpath根目錄
    此外,如果你在同一優(yōu)先級位置同時有application.properties和application.yml,那么application.yml里的屬性會覆蓋application.properties里的屬性
  1. 自動配置微調

在Spring Boot里有300多個屬性可以用來微調應用程序里的Bean。
例如,通過application.yml來更改嵌入式服務器端口:

server:
  port: 8000
  1. 應用程序的Bean的配置外置

假設我們在application.yml配置了如下信息:

person:
  name: 張三
  age: 20

想要在某個類上拿到剛剛所配置的信息,那很簡單,只需在類上配置如下注解,即可在該用的地方使用剛剛配置的屬性:
@ConfigurationProperties(prefix = "person")

當然,我們也可以在一個Bean里加載配置屬性:

package com.jasonper.readinglist;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("person") // 從application.yml里的person中獲得屬性
public class PersonProperties {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
  1. 使用Profile進行配置
    當應用程序需要部署到不同的運行環(huán)境時,一些配置細節(jié)通常會有所不同。比如數(shù)據(jù)庫連接在開發(fā)環(huán)境和生產環(huán)境下就會不一樣,在測試環(huán)境下又不一樣。此時可以使用Profile。Profile是一種條件化配置,基于運行時激活的Profile,會使用或者忽略不同的Bean或配置類。
    以Spring Security為例:
@Profile("production")
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    ...
}

這里的@Profile注解要求運行時激活production Profile,這樣才能應用該配置。激活配置的方式有很多種,這里使用application.yml文件來激活:

spring:
  profiles:
    active: production
  1. 使用特定于Profile的屬性文件

如果你正在使用application.properties,可以創(chuàng)建額外的屬性文件,遵循application-{profile}.properties這種命名格式,這樣就能提供特定于Profile的屬性了。

  1. 使用多Profile YAML文件進行配置

如果使用YAML來配置屬性,則可以遵循與配置文件相同的命名規(guī)范:application-{profile}.yml這樣的YAML文件,并將與Profile無關的屬性繼續(xù)配置在application.yml里。

同時,可以把所有的Profile的配置屬性都放在同一個application.yml文件里。使用日志配置來舉個例子:

logging:
  level: 
    root: INFO
    
---
spring:
  profiles: dev

logging:
  level: 
    root: DEBUG

---

spring:
  profiles: production

logging:
  path: /tmp/
  file: BookWorm.log
  level:
    root: WARN

這個application.yml分為三部分,使用一組三個連字符作為分隔符。第二段和第三段分別指定了不同的環(huán)境下的日志配置。第二段是開發(fā)環(huán)境下的,第三段是生產環(huán)境下的。
另一方面,第一段未指定spring.profile,因此這里的屬性對全部Profile都生效,或者對那些未設置該屬性的激活Profile生效。

3.定制應用程序的錯誤頁面

定制應用程序的錯誤頁面,只需在src/main/resources/templates中加入自己寫的錯誤頁面即可。Spring Boot會為錯誤視圖提供如下錯誤屬性:

  • timestamp:錯誤發(fā)生的時間
  • status:錯誤狀態(tài)碼
  • error:錯誤的原因
  • exception:異常的類型
  • message:異常消息(如果這個錯誤是由異常引起的)
  • errors:BindingResult異常里的各種錯誤(如果這個錯誤是由異常引起的)
  • trace:異常跟蹤信息(如果這個錯誤是由異常引起的)
  • path:錯誤發(fā)生時請求的url路徑
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容