Spring Boot 條件化自動裝配
不知道大家有沒有遇到過pom檔案中加入 spring-boot-starter-jdbc
這個jar之後,在不做任何處理的時候,會報如下錯誤;
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-09-28 19:32:51.878 ERROR 34836 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
這是因為沒有配置資料源的原因導緻的,可是問題來了,我隻是加了個jar,但是Spring Boot 如何做到加這個jar就必須要配置資料源呢?
我們可以進入
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration
中看下,其中有一段這樣的代碼
/**
* Hikari DataSource configuration.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true)
static class Hikari {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
`注:spring boot 預設的是hikari``
原來是通過一些注解做到的;
Class條件注解
@ConditionalOnClass (當指定類存在時)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
/**
* The classes that must be present. Since this annotation is parsed by loading class
* bytecode, it is safe to specify classes here that may ultimately not be on the
* classpath, only if this annotation is directly on the affected component and
* <b>not</b> if this annotation is used as a composed, meta-annotation. In order to
* use this annotation as a meta-annotation, only use the {@link #name} attribute.
* @return the classes that must be present
*/
Class<?>[] value() default {};
/**
* The classes names that must be present.
* @return the class names that must be present.
*/
String[] name() default {};
}
@ConditionalOnMissingClass (當指定類缺失時)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnMissingClass {
/**
* The names of the classes that must not be present.
* @return the names of the classes that must not be present
*/
String[] value() default {};
}
注:
@ConditionalOnMissingClass
注解在spring boot 在各個版本都不同的改動。
Bean條件注解
@ConditionalOnBean (當指定Bean存在)
@ConditionalOnMissingBean(當指定Bean不存在)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
/**
* The class types of beans that should be checked. The condition matches when beans
* of all classes specified are contained in the {@link BeanFactory}.
* @return the class types of beans to check
*/
Class<?>[] value() default {};
/**
* The class type names of beans that should be checked. The condition matches when
* beans of all classes specified are contained in the {@link BeanFactory}.
* @return the class type names of beans to check
*/
String[] type() default {};
/**
* The annotation type decorating a bean that should be checked. The condition matches
* when all of the annotations specified are defined on beans in the
* {@link BeanFactory}.
* @return the class-level annotation types to check
*/
Class<? extends Annotation>[] annotation() default {};
/**
* The names of beans to check. The condition matches when all of the bean names
* specified are contained in the {@link BeanFactory}.
* @return the names of beans to check
*/
String[] name() default {};
/**
* Strategy to decide if the application context hierarchy (parent contexts) should be
* considered.
* @return the search strategy
*/
SearchStrategy search() default SearchStrategy.ALL;
/**
* Additional classes that may contain the specified bean types within their generic
* parameters. For example, an annotation declaring {@code value=Name.class} and
* {@code parameterizedContainer=NameRegistration.class} would detect both
* {@code Name} and {@code NameRegistration<Name>}.
* @return the container types
* @since 2.1.0
*/
Class<?>[] parameterizedContainer() default {};
}
- value 類型安全的屬性設定
- type 當類型不存在時的屬性設定
- annotation 當bean标注了某種注解類型時
- name 指定具體bean名稱
- search 三種應用上下文搜尋政策;目前、父級所有
- parameterizedContainer 泛型
屬性條件注解
@ConditionalOnProperty
String[] value() default {};
// 配置屬性名字首
String prefix() default "";
// 配置屬性名,如果prefix不為空則值為 prefix+name
String[] name() default {};
// 表示期望屬性的值
String havingValue() default "";
// 用于判斷屬性值不存在的時候是否比對
boolean matchIfMissing() default false;
條件注解還有很多,如下
@ConditionalOnClass : classpath中存在該類時起效
@ConditionalOnMissingClass : classpath中不存在該類時起效
@ConditionalOnBean : DI容器中存在該類型Bean時起效
@ConditionalOnMissingBean : DI容器中不存在該類型Bean時起效
@ConditionalOnSingleCandidate : DI容器中該類型Bean隻有一個或@Primary的隻有一個時起效
@ConditionalOnExpression : SpEL表達式結果為true時
@ConditionalOnProperty : 參數設定或者值一緻時起效
@ConditionalOnResource : 指定的檔案存在時起效
@ConditionalOnJndi : 指定的JNDI存在時起效
@ConditionalOnJava : 指定的Java版本存在時起效
@ConditionalOnWebApplication : Web應用環境下起效
@ConditionalOnNotWebApplication : 非Web應用環境下起效
具體使用時,可以檢視使用方法