@SpringBootApplication注解探究

作用

@SpringBootApplication注解标注在类上,注明该类为SpringBoot的主配置类,运行该类的main方法来启动一个SpringBoot的应用.
该注解中,由标注了一堆组合注解.后续由各组合注解展开

@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 {

@SpringBootConfiguration

标注在某个类上表示是SpringBoot的一个配置类.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 这个注解用来标识这是一个配置类
@Configuration
public @interface SpringBootConfiguration {

}

@Configuration
这个注解是Spring中定义的,来源于org.springframework.context.annotation包下,用来标识一个配置类.

SpringBoot中的配置类可以理解为之前SSM开发中的配置文件

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

通过看@Configuration注解的源码,可以看到,配置类其实也是容器中的一个组件.
在这里插入图片描述

@EnableAutoConfiguration

这个注解是org.springframework.boot.autoconfigure包下定义的.

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

这个注解是用来告诉SpringBoot以开启自动配置功能.
之前需要自己配置的东西,SpringBoot会帮我们自动配置,使用@EnableAutoConfiguration注解以后,自动配置才会生效

在这个注解中有两个组合注解,需要格外注意:

  • @AutoConfigurationPackage
    这个注解的意思是自动配置包,看一下它的源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

在这个注解中,使用了一个关键注解@import
在这里插入图片描述
@import注解是源于Spring中的org.springframework.context.annotation.Import包下,是Spring中的一个底层注解,作用是给容器中导入一个组件
在这里导入了一个AutoConfigurationPackages.Registrar.class

@Import(AutoConfigurationPackages.Registrar.class)

接下来看一下Registrar的源码

	@Order(Ordered.HIGHEST_PRECEDENCE)
	static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata,
				BeanDefinitionRegistry registry) {
			register(registry, new PackageImport(metadata).getPackageName());
		}

		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.<Object>singleton(new PackageImport(metadata));
		}

	}

起关键作用的代码是下边这一段

		@Override
		// 这里的metedata是获取注解@SpringBootApplication的元数据,
		public void registerBeanDefinitions(AnnotationMetadata metadata,
				BeanDefinitionRegistry registry) {
				// 我们可以通过debug的方式查看注解的元数据,获取到的是@SpringBootApplication这个注解
				// getPackageName()方法获取标注@SpringBootApplication注解所在的主配置的包路径
			register(registry, new PackageImport(metadata).getPackageName());
		}

registerBeanDefinitions()方法通过注解的元数据,将主配置类(@SpringBootApplication标注的类)所在包及下边所有子包里的组件扫描到Spring容器中

  • @Import(EnableAutoConfigurationImportSelector.class)
    这个注解给容器中导入了EnableAutoConfigurationImportSelector组件
    (EnableAutoConfigurationImportSelector:开启自动配置导包选择器,也就是导入哪些组件的选择器)
@Deprecated
public class EnableAutoConfigurationImportSelector
		extends AutoConfigurationImportSelector {

	@Override
	protected boolean isEnabled(AnnotationMetadata metadata) {
		if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
			return getEnvironment().getProperty(
					EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
		}
		return true;
	}

}

这个导包选择器中只有一个用来判断的isEnabled()方法,主要关注的是它的父类.

public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {
	
	// 这是一个需要注意的关键方法	
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		try {
			AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
					.loadMetadata(this.beanClassLoader);
			AnnotationAttributes attributes = getAttributes(annotationMetadata);
			// 返回了一个集合,集合中维护了所有需要导入的自动配置类
			List<String> configurations = getCandidateConfigurations(annotationMetadata,
					attributes);
			configurations = removeDuplicates(configurations);
			configurations = sort(configurations, autoConfigurationMetadata);
			Set<String> exclusions = getExclusions(annotationMetadata, attributes);
			checkExcludedClasses(configurations, exclusions);
			configurations.removeAll(exclusions);
			configurations = filter(configurations, autoConfigurationMetadata);
			fireAutoConfigurationImportEvents(configurations, exclusions);
			return configurations.toArray(new String[configurations.size()]);
		}
		catch (IOException ex) {
			throw new IllegalStateException(ex);
		}
	}
}

selectImports()在这个方法中,会将所有需要导入的组件以全类名的方式返回,接着这些组件就会添加到Spring的容器当中.
在这里,再次以debug的方式,进入这个方法.我们可以看到,方法的参数annotationMetadata注解的元数据.这里的注解是@SpringBootApplication.
在这里插入图片描述
接着放行,可以看到这里返回了一个集合configurations.这个集合中维护了所有需要导入的自动配置类.
在这里插入图片描述
需要导入的自动配置类的一部分:
在这里插入图片描述
这些自动配置类,给Spring的容器中导入了某个场景所需要的所有组件,并配置好这些组件.通过这些自动配置类,就省去了我们手动编写配置注入功能的工作.

这些自动配置类从何而来呢?
主要通过这个方法:
在这里插入图片描述

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		// 在这里获取自动配置类
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
				// 第一个参数:getSpringFactoriesLoaderFactoryClass()方法,返回了EnableAutoConfiguration.class的Class对象
				// 第二个参数:传入了一个类加载器,在下个代码块中详解.
				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;
	}

getCandidateConfigurations()方法做的事情是:从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值.

// 第一个参数factoryClass传入的是EnableAutoConfiguration
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		try {
			// 通过类加载器去加载类路径下的META-INF/spring.factories中指定的自动配置类文件
			Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			List<String> result = new ArrayList<String>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				// 把加载到的自动配置类读取为一个Properties文件
				Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
				// 读取EnableAutoConfiguration指定的自动配置类的值
				String factoryClassNames = properties.getProperty(factoryClassName);
				result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
			}
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
					"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

EnableAutoConfiguration指定的自动配置类在org.springframework.boot.autoconfigure.META-INF下
在这里插入图片描述
随便进入其中一个自动配置类,以WebMvcAutoConfiguration为例
在自动配置类中通过@Bean注解将组件添加到Spring容器中,以实现自动配置.
在这里插入图片描述
在Spring-Boot中通过上述的方式,将繁琐的配置文件变为官方配置整合好的一个个配置类,实现无配置J2EE开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值