1.SpringBoot主动配置简介
2.SpringBoot主动配置是如何实现的
1.SpringBoot主动配置简介
个别状况下,咱们在学习springBoot之前,都会先学习spring和spring MVC,咱们须要手动配置十分多的类,比方注解扫描器,dispatcherServlet等等。然而到咱们学习了SpringBoot当前,发现springBoot是开箱即用的,不须要任何配置,就一个main办法,就能够帮咱们把包扫描进来,且配置好很多的组件,整合其它框架也十分不便。
2.SpringBoot主动配置是如何实现的
2.1 @SpringBootApplication
当咱们创立一个springBoot我的项目的时候,就会有一个主类,咱们会发现有一个注解@SpringBootApplication
@SpringBootApplicationpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}
@SpringBootApplication标记的类代表这个类是SpringBoot的主配置类,启动@SpringBootApplication标注的类就能够启动该容器。
咱们往这个注解里看,会发现这个注解是由一系列注解组成的:
@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@EnableAutoConfiguration@ComponentScan
接下来咱们围绕这三个注解开展解析,就能够明确SpringBoot主动配置原理了。
2.2 @SpringBootConfiguration
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configuration@Indexedpublic @interface SpringBootConfiguration { @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true;}
此注解非常容易,其成果等同于@Configuration,代表了此类是一个配置类,会被注入到spring容器中。
2.3 @ComponentScan
它是一个包扫描注解,能够输出basePackages包名来示意被扫描的包的门路,然而这里并没有这样应用。
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
在@SpringBootApplication注解中,
type = FilterType.CUSTOM 示意依照自定义形式排除组件
classes = TypeExcludeFilter.class 具体的排除形式实现类
2.4 @EnableAutoConfiguration
@EnableAutoConfiguration:意为开启主动配置,是主动配置最重要的一个注解。
咱们能够往里点击:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {}
它由以下两个注解组成:
@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)
2.5 @AutoConfigurationPackage
@AutoConfigurationPackage:意为主动配置包。往里点击,咱们能够看出它往spring里导入了一个类Registrar:
@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage {}
而Registrar类,它实现了ImportBeanDefinitionRegistrar接口,看见这个类的名字和实现的办法就应该明确,它是将一些类导入到咱们的容器当中的。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); } }
咱们打一个断点就会发现:
@AutoConfigurationPackage 就是将主配置类(@SpringBootApplication 标注的类)所在的包上面所有的组件都扫描注册到spring 容器中。(这就能够解释为什么主配置类所在门路下的组件能够被扫描到spring容器中。)
2.6 @Import(AutoConfigurationImportSelector.class)
@Import(AutoConfigurationImportSelector.class):意为导入主动配置类,而且是有选择性地导入。
咱们看一下AutoConfigurationImportSelector类,会发现有一个selectImports办法,这个办法就是返回哪些主动配置类须要导入的办法:
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
咱们看getAutoConfigurationEntry办法:
protected AutoConfigurationEntry getAutoConfigurationEntry(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 = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions);}
从上述代码咱们能够得出,咱们在读取了主动配置类当前,再通过去重,排除等各种操作,能够返回最终的配置类,咱们只须要关注最重要的读取主动配置类的办法就行了。
能够看出以下办法为要害办法:
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
持续往里点击
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = new ArrayList<>( SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())); ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
咱们能够得出,只有configurations返回且不为空,否则就会提醒META-INF/spring.factories 或者 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports门路下没有找到须要加载的文件,请确认文件地位是否正确。
而且,咱们间断点击loadFactoryNames和load办法,会发现他们别离加载了所有jar包下的classpath门路下的META-INF/spring.factories文件和META-INF/spring/%s.imports文件。
主动配置类提前就被写好了,而且所有主动配置类都在这个文件中一一列举结束,咱们能力将它读取进spring容器,无需写很多的主动配置类。
比方咱们的AopAutoConfiguration。
当咱们自定义AOP主动配置类的时候,会应用咱们本人配置的,否则就是用默认的配置。