天天看點

【spring系列】Spring Boot 條件化自動裝配Spring Boot 條件化自動裝配

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應用環境下起效

具體使用時,可以檢視使用方法

繼續閱讀