Spring Boot @EnableAutoConfiguration和 @Configuration的區別


Spring Boot @EnableAutoConfiguration和
@Configuration的區別

在Spring Boot中,我們會使用@SpringBootApplication來開啟Spring Boot程序。在之前的文章中我們講到了@SpringBootApplication相當於@EnableAutoConfiguration,@ComponentScan,@Configuration三者的集合。

其中@Configuration用在類上面,表明這個是個配置類,如下所示:

@Configuration
public class MySQLAutoconfiguration {
    ...
}

而@EnableAutoConfiguration則是開啟Spring Boot的自動配置功能。什么是自動配置功能呢?簡單點說就是Spring Boot根據依賴中的jar包,自動選擇實例化某些配置。

接下來我們看一下@EnableAutoConfiguration是怎么工作的。

先看一下@EnableAutoConfiguration的定義:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */
	Class<?>[] exclude() default {};

	/** * Exclude specific auto-configuration class names such that they will never be * applied. * @return the class names to exclude * @since 1.3.0 */
	String[] excludeName() default {};

}

注意這一行: @Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector實現了ImportSelector接口,並會在實例化時調用selectImports。下面是其方法:

	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
				annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

這個方法中的getCandidateConfigurations會從類加載器中查找所有的META-INF/spring.factories,並加載其中實現了@EnableAutoConfiguration的類。 有興趣的朋友可以具體研究一下這個方法的實現。

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

我們再看一下spring-boot-autoconfigure-2.2.2.RELEASE.jar中的META-INF/spring.factories。

spring.factories里面的內容是key=value形式的,我們重點關注一下EnableAutoConfiguration:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
...

這里只列出了一部分內容,根據上面的代碼, 所有的EnableAutoConfiguration的實現都會被自動加載。這就是自動加載的原理了。

如果我們仔細去看具體的實現:

@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(JmxAutoConfiguration.class)
@ConditionalOnProperty(prefix = "spring.application.admin", value = "enabled", havingValue = "true",
		matchIfMissing = false)
public class SpringApplicationAdminJmxAutoConfiguration {

可以看到里面使用了很多@Conditional*** 的注解,這種注解的作用就是判斷該配置類在什么時候能夠起作用。

更多教程請參考 flydean的博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM