Spring 幾個配置註解的含義
說說以下幾個註解的含義
[email protected]此註解的用義是讓一個類成為一個配置類,它與 @Bean 註解一起使用(一般用在類中的方法上面),可以用於生成一系列的 Bean .它們是用來簡單基於 xml 配置 Bean 的註解。可以這樣說,一個類上面 @Configuration 就相當於一個 定義 很多Bean 的 xml 檔案。
[email protected]此註解的用義是讓一個類成為一個注入了 propeties 變數的配置類,一般與 @Component 和 @PropertySource 一起使用,例如:
@Component @PropertySource("classpath:application.properties")@ConfigurationProperties(prefix="hrService")
public class HRConfig意思是,HRConfig 是一個裝配了 propeties 的配置類(@ConfigurationProperties),裝配變數的檔案是 classpath:application.properties ,(@PropertySource(...)),讀取檔案中變數的規則是,所有以 hrService 為字首的變數, 可以對外提供讀取配置變數的服務(@Component)。
上面的配置其實可以在 Spingboot 中簡化為
@Component@ConfigurationProperties因為 Springboot 中 classpath:application.properties 是預設載入的配置檔案。(prefix="hrService")
@ConfigurationProperties 此註釋從字面上來理解,可以設定配置的屬性,使被裝配類有不同的行為.例如,可以傳入 prefix,ignoreUnknowFields 等等,以達到裝配行為多樣化。其實它並不真正具體一個對外提供配置的能力,@ConfigurationProperties 只是規定了一個類如何成為一個配置服務類,但並不使它真正成為一個配置服務類。使它具備這種能力也即使它成為一個 Bean,@Conponent 就能做到,@EnableConfigurationProperties 也能做取。
[email protected] 允許任意一個類具有對外提供配置的能力。它與 @Bean 的方式不同,@Bean 是配置在類本身上,一勞永逸,一旦配置,任何地方都可以注入。而 @EnableConfigurationProperties 是配置在希望使用此配置服務的那個類上面。這樣就可以實現可拔插。下面拷貝一份程式碼以說明:
@ConfigurationProperties(
prefix = "fps",
ignoreUnknownFields = true
)
@Data
public class FpsProperties {
private String host="localhost";
private int port=7008;
private String username;
private String password;
private String orgid="99996";
private int connectTimeout=10000;
private int connectRequestTimeout=10000;
private int socketTimeout=120000;//相當於讀超時
private int retryCount=3;//重試次數
private boolean fpsEnabled=true;
}
//-------------------------------------------------------------------------------
@Configuration
@EnableConfigurationProperties({FpsProperties.class})
@ConditionalOnClass({FpsClient.class})
@ConditionalOnProperty(
prefix = "fps",
name = {"enabled"},
matchIfMissing = true
)
@Slf4j
public class FpsAutoConfiguration {
@Autowired
private FpsProperties fpsProperties;
@Bean
@ConditionalOnMissingBean
@ConfigurationProperties(
prefix = "fps"
)
public FpsService fpsService() {
FpsServiceImpl fpsService = new FpsServiceImpl(fpsProperties.getUsername(), fpsProperties.getPassword(), fpsProperties.getHost(), fpsProperties.getPort(), fpsProperties.getOrgid(), fpsProperties.getConnectRequestTimeout(), fpsProperties.getConnectTimeout(), fpsProperties.getSocketTimeout());
return fpsService;
}
}
首先,@configuration 表示 FpsAutoConfiguration 類是一個可生成多個 Bean 的配置器。@EnableConfigurationProperties({FpsProperties.class}) 表示使 FpsProperties 這個類擁有對“我”提供配置的能力。類裡面的 @Autowired 就把這種配置能力注入進來了。@ConditionalOnClass({FpsClient.class}) 表示當整個 jvm 中存在 FpsClient 這個類時,本 @Configuration 才生效,否則不生效。當時看這個配置非常疑惑,如果 FpsClient 這個類不存在,此行程式碼應該會立即報錯,何談載入到 jvm 中去執行呢?解釋一下,@conditionalOnClass 一般是在庫中使用的,假設庫工程是 A,有上面的程式碼。另有一個關聯工程 B,A 中沒有 FpsClient 類,而 B 中有,讓 A 工程依賴於 B,將 A 打包,A.jar 作為一個庫對外發布。此時,A.jar 是沒有 FpsClient 類的定義的。此時,有一個客戶工程,付費了,想使用 A.jar ,而 C 沒有定義 FpsClient 類,所以 A.jar 中的上述配置就不會生效,因此,C 在執行時,就不會承擔 A 裡面產生的 Bean 的負擔。就這是熱拔插的意思。所以 @ConditionalOnClass 是為了完成這件事情的。
@ConditionalOnProperty 與 @ConditionalOnClass 目的一致,邏輯上是且的關係,只要 @ConditionalOnProperty 中規定的條件沒有滿足,整個 @Configuration 就不生效。上面的配置中,規定了配置變數 fps.enabled=true 時,@Configuration 才生效。
一般情況下,若變數是 fps.x.y.z.enabled,則上面要寫為:prefix="fps.x.y.z", name={"enabled"}。這是因為 name 一定是最終的名字,而不含有任何字首。
後面類裡面的,@Bean 就會很熟悉了,表示定義一個 Bean 生成的條件,依賴的變數和生成的步驟。@ConditionalOnMissingBean 表示此 Bean 生成的規則:只有當這個類的 Bean 沒有生成時,才會去生成 Bean. @ConfigurationProperties 其實是多餘的,因為後面的程式碼直接使用了 FpsProperties 去取值.
上面生成 FpsServiceImpl 的 Bean 其實可以更簡單:
FpsServiceImpl fpsService = new FpsServiceImpl();//前提是有無參構造方法
此時 @ConfigurationProperties 表示去FpsProperties 中找變數的值,還是預設配置檔案 application.properties 中按 prefix = fps 去讀呢。這個問題可能沒有意義,首先要明確一點,所有配置類的配置載入器是同一個,不可能存在不同的值,至於存在同名的多個配置檔案,載入的是哪一個就要具體看了,一般是後面載入的會替換前面載入的。因此,上面的問題就不用回答的。
另外,使用了此註解的類所在的包及子包下面的類也預設使用了此註解。若將此註解應用到根目錄包下面的類,則所有類也都應用了此註解。所以此註解的使用一般要放在最高階的根目錄類上面。
關於這個註解,最後再舉一個例:
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class MyBatisConfig {
// @Value("${spring.datasource.encode-password}")
// private String encodePassword;
@Autowired
private DataSourceProperties properties;
//這個配置會載入所有spring.datasource配置注入DataSource物件,未載入會有問題。
@Bean
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
public DataSource dataSource() {
// Assert.isNull(this.properties.getPassword(), "必須為空否則,加密密碼會被覆蓋");
DataSourceBuilder factory = DataSourceBuilder
.create(this.properties.getClassLoader())
.driverClassName(this.properties.getDriverClassName())
.url(this.properties.getUrl()).username(this.properties.getUsername())
.password(properties.getPassword());
if (this.properties.getType() != null) {
factory.type(this.properties.getType());
}
BasicDataSource basicDataSource= (BasicDataSource)factory.build();
basicDataSource.setMaxTotal(150);
basicDataSource.setMaxWaitMillis(5000);
return basicDataSource;
}
@Bean(name = "sqlSessionFactory")
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setTypeAliasesPackage("com.******.entity");
//分頁外掛
PageHelper pageHelper = new PageHelper();
Properties properties = new Properties();
properties.setProperty("reasonable", "true");
properties.setProperty("supportMethodsArguments", "true");
properties.setProperty("returnPageInfo", "check");
properties.setProperty("params", "count=countSql");
pageHelper.setProperties(properties);
//新增外掛
bean.setPlugins(new Interceptor[]{pageHelper});
//新增XML目錄
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return bean.getObject();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
4.@EnableAutoconfiguration 這個註解作用在於讓 Spring Boot 根據應用所宣告的依賴來對 Spring 框架進行自動配置,比較智慧的是,它還根據 classpath 中的 jar 包推斷需要引入哪些註解/ Bean ,另外,使用了此註解的類所在的包及子包下面的類也預設使用了此註解。若將此註解應用到根目錄包下面的類,則所有類也都應用了此註解,這也是最通常的做法,實際上, @SpingBootApplication 註解就使用了這個註解。詳細的說明可以參看 EnableAutoconfiguration 註解實現檔案的說明。
@Configuration @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) public class MyConfiguration { }