Spring学习笔记-Spring boot中@SpringBootApplication 注解初探

Spring学习笔记-Spring boot中@SpringBootApplication 注解初探

特殊说明:代码块中的"…" 旨在屏蔽一些不太重要的代码

  • 在SpringBoot的启动上加上@SpringBootApplication注解就可以简捷的创建一个Spring boot 应用程序,接下来对该注解进行一个初步的探索,以了解其背后的原理。
@SpringBootApplication
public class Application {

	public static void main(String[] args) {

	    SpringApplication.run(Application.class, args);
	}

}
  • SpringBootApplication是一个组合注解,主要包括了@SpringBootConfiguration、@ComponentScan、@EnableAutoConfiguration三个注解。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    ......
}
  • 首先来看@SpringBootConfiguration,该注解主要包含了一个@Configuration注解,@Configuration注解主要被一个@Component注解标注。其中@Configuration在学习Spring的时候了解到该被该注解标注说明该类为一个配置类,由此可以得出@SpringBootConfiguration注解主要用来告诉Spring 容器被其标注的类为java配置类。
@Configuration
public @interface SpringBootConfiguration {
}

@Component
public @interface Configuration {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}
  • 其次再来看@EnableAutoConfiguration,该注解主要包含@AutoConfigurationPackage、@Import({AutoConfigurationImportSelector.class})两个注解,其中@AutoConfigurationPackage注解主要包含了一个@Import({Registrar.class}),即@EnableAutoConfiguration注解,主要是通过@import导入了Registrar.class和AutoConfigurationImportSelector.class两个java配置类。
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
	......
}

@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
  • Registrar.class主要通过实现ImportBeanDefinitionRegistrar, DeterminableImports两个接口,重写 registerBeanDefinitions方法将注解所在包及其子包下的所有组件注册进容器中 。由此可以得出为什么需要把被@SpringBootApplication标注的启动类放在其他类的父包或同一包中
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
	......
	 拿到注解的全信息,注解所在包及其子包下的组件
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
		AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
	}
	......

}
  • AutoConfigurationImportSelector.class 主要通过selectImports方法中调用的getAutoConfigurationEntry方法进而调用getCandidateConfigurations方法 来获取spring-boot-autoconfigure-2.1.0.RELEASE.jar包下"META-INF/spring.factories"中的自动配置实体类。所有的自动配置类都在该properties文件中,但是这里的配置类并不会全部被导入,很多配置类上有@ConditionalOnClass这样的一个注解。只有在符合@ConditionalOnClass注解条件下的配置类才会被加载,这就是为什么我们在pom.xml只导入一个spring-boot-starter-web就会自动装配web的相关配置,省去了以前手动配置xml的步骤。
// 选择导入的配置类
public String[] selectImports(AnnotationMetadata annotationMetadata) {
	......
    AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
    ......
}

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
    ......
    List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
    ......
}

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    ......
}

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
	if (result != null) {
		return result;
	} else {
		try {
			Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
			LinkedMultiValueMap result = new LinkedMultiValueMap();

			while(urls.hasMoreElements()) {
				URL url = (URL)urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				Iterator var6 = properties.entrySet().iterator();
	
				while(var6.hasNext()) {
					Entry<?, ?> entry = (Entry)var6.next();
					String factoryClassName = ((String)entry.getKey()).trim();
					String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
					int var10 = var9.length;
	
					for(int var11 = 0; var11 < var10; ++var11) {
						String factoryName = var9[var11];
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
	
			cache.put(classLoader, result);
			return result;
		} catch (IOException var13) {
			throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
		}
	}
 }
  • 最后的@ComponentScan注解,就是扫描当前配置类及其当前类所在包和子包下的组件
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值