springboot自动配置

1. 代码

  • springboot项目主类上有注解@SpringBootApplication,该注解中引入注解@EnableAutoConfiguration注解开启自动配置,@EnableAutoConfiguration中通过引入注解@Import(AutoConfigurarionImportSelector.class)导入一系列bean组件。
  • 其中,AutoConfigurationImportSelector是DeferedImportSelector的实现类,DeferedImportSelector是ImportSelector的实现类,ImportSelector接口有一个方法String[] selectImports(AnnotationMetadata importingClassMetadata);
  • 通过实现ImportSelector接口并重写selectImports方法来指定要导入到容器中的组件的全类名
@SpringBootApplication
public class HelloMain {
    public static void main(String[] args) {
        SpringApplication.run(HelloMain.class,args);
    }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
//实现了DeferedImportSelector->ImportSelector,并重写了selectImports方法
AutoConfigurationImportSelector.java
    @Override
	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());
	}

    protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//获取候选配置
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		//移除重复配置
		configurations = removeDuplicates(configurations);
		//获取需要排除的配置并排除之
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	//通过指定的classLoader来获取一系列的要导入的组件的全限定类名
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

下图即获得的要导入的类的全限定类名。
在这里插入图片描述

-
SpringFactoriesLoader.java

	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	//factoryTypeName="org.springframework.boot.autoconfigure.EnableAutoConfiguration"
		String factoryTypeName = factoryType.getName();
		//获取到所有需要导入的组件的全限定类名Map后,
		//get以EnableAutoConfiguration为key的组件
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}

	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}
        //public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
        //the location to look for fatories. Can be present in multiple JAR files.
        //META-INF/spring.factories可能被包含在多个jar包中
		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-autoconfiguration.jar中包含该文件,文件部分内容如下:

# 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

2. 自动配置的例子

  • 配置端口时在application.properties文件中设置server.port=8083
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
//在类路径下有指定类时才使xxxAutoConfiguration类生效
//@Conditional注解可以通过条件控制是否注入Bean
@ConditionalOnClass(ServletRequest.class)
//当spring服务为servlet web时,当前AutoConfiguraion类生效
@ConditionalOnWebApplication(type = Type.SERVLET)
//使使用@ConfiguraionProperties注解的类生效
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

其中,ServerProperties类如下:

//配置的前缀为server
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

	/**
	 * Server HTTP port.
	 */
	private Integer port;

	/**
	 * Network address to which the server should bind.
	 */
	private InetAddress address;

点ServerProperties中的port即可看到其在application.properties中定义了
在这里插入图片描述
@EnbaleConfigurationProperties注解的作用为:

 * Enable support for {@link ConfigurationProperties @ConfigurationProperties} annotated
 * beans. {@code @ConfigurationProperties} beans can be registered in the standard way
 * (for example using {@link Bean @Bean} methods) or, for convenience, can be specified
 * directly on this annotation.

启用对带有@ConfigurationProperties注解的Bean的支持。@ConfigurationProperties beans可以使用标准方式注册(使用@Bean注解),也可以直接在这个注解(@EnableConfigurationProperties)上指定。

通过@ConfigurationProperties使用外部配置填充Bean属性的几种方法

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值