共计 8766 个字符,预计需要花费 22 分钟才能阅读完成。
springApplication
一、@SpringBootApplication
的作用是什么?
Q:springboot 项目的启动类上,都会有个注解@SpringBootApplication
,这个注解起到了什么作用?
@SpringBootApplication
public class MicroServiceApplication {public static void main(String[] args) {SpringApplication.run(MicroServiceApplication.class, args);
}
}
我们进入 @SpringBootApplication
注解,发现它 等价于三个注解:@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {...}
1)@SpringBootConfiguration
就相当于 @Configuration
@Configuration
public @interface SpringBootConfiguration {}
2)@EnabelAutoConfiguration
相当于将这两个类的实例加入到容器中AutoConfigurationImportSelector.class
AutoConfigurationPackages.Registrar.class
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {...}
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}
-
AutoConfigurationImportSelector.class
的作用是,注入 spring.factories 文件中 EnableAutoConfiguration 对应的类的实例,当然要经过 spring.factories 文件中 AutoConfigurationImportFilter 对应的过滤器(OnBeanCondition
、OnClassCondition
、OnWebApplicationCondition
等等)的过滤。还要排除掉@EnableAutoConfiguration
中的 exclude 和 excludeName具体见
ConfigurationClassParser
的 getImports 方法,其中调用了AutoConfigurationImportSelector
的 process 方法和 selectImports 方法。public Iterable<Group.Entry> getImports() {for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector()); } return this.group.selectImports();}
AutoConfigurationImportSelector
实现了DeferredImportSelector
,所以它是解析@Configuration
的最后一步。DeferredImportSelector
可以和@Order
搭配使用。AutoConfigurationImportSelector
的意义在于引入其他包时,可以直接注入其他包的@Configuration
,当然需要在其他包的 resources 文件夹下,新建 META-INF 目录,在 META-INF 目录下新建 spring.factories 文件,加入 org.springframework.boot.autoconfigure.EnableAutoConfiguration = @Configuration 标注的类的路径
-
AutoConfigurationPackages.Registrar.class
的作用是,注入一个名称为 AutoConfigurationPackages 的BasePackages.class
实例。这个实例的作用在于保存自动扫描的包路径,供以后使用(比如 JPA 的 entity 扫描)public static void register(BeanDefinitionRegistry registry, String... packageNames) {if (registry.containsBeanDefinition(BEAN)) {BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN); ConstructorArgumentValues constructorArguments = beanDefinition .getConstructorArgumentValues(); constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames)); } else {GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(BasePackages.class); beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(BEAN, beanDefinition); } } private static String[] addBasePackages(ConstructorArgumentValues constructorArguments, String[] packageNames) {String[] existing = (String[]) constructorArguments .getIndexedArgumentValue(0, String[].class).getValue(); Set<String> merged = new LinkedHashSet<>(); merged.addAll(Arrays.asList(existing)); merged.addAll(Arrays.asList(packageNames)); return StringUtils.toStringArray(merged); }
3)@ComponentScan
当然是将路径下合适的类加载到容器中
Q:它为什么要用到TypeExcludeFilter.class
和AutoConfigurationExcludeFilter.class
这两个过滤器
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {...}
-
这两个过滤器在
ComponentScanAnnotationParser
的 parse 方法中,被加入public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { // 此处加入了三个默认的 includeFilter,一个用来筛选 @Componment 标记的类,一个用来筛选 javax.annotation.ManagedBean 标记的类,一个用来筛选 JSR-330 中 javax.inject.Named 标记的类(如果引入了 JSR-330 依赖注入标准的话,即引入 javax.inject 包)ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); ... for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {for (TypeFilter typeFilter : typeFiltersFor(filter)) {scanner.addExcludeFilter(typeFilter); } } ... scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) { @Override protected boolean matchClassName(String className) {return declaringClass.equals(className); } }); return scanner.doScan(StringUtils.toStringArray(basePackages)); }
** 也是在 parse 这个方法里调用了 typeFiltersFor 方法,对 `TypeFilter.class` 的实现类进行了实例化 **。(也就是说 `TypeExcludeFilter.class` `AutoConfigurationExcludeFilter.class` `AbstractTypeHierarchyTraversingFilter.class` 都在这里进行了实例化,但是没有加入 spring 的 bean 池)
private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {List<TypeFilter> typeFilters = new ArrayList<>(); FilterType filterType = filterAttributes.getEnum("type"); for (Class<?> filterClass : filterAttributes.getClassArray("classes")) {switch (filterType) { case ANNOTATION: Assert.isAssignable(Annotation.class, filterClass, "@ComponentScan ANNOTATION type filter requires an annotation type"); @SuppressWarnings("unchecked") Class<Annotation> annotationType = (Class<Annotation>) filterClass; typeFilters.add(new AnnotationTypeFilter(annotationType)); break; case ASSIGNABLE_TYPE: typeFilters.add(new AssignableTypeFilter(filterClass)); break; case CUSTOM: Assert.isAssignable(TypeFilter.class, filterClass, "@ComponentScan CUSTOM type filter requires a TypeFilter implementation"); TypeFilter filter = BeanUtils.instantiateClass(filterClass, TypeFilter.class); ParserStrategyUtils.invokeAwareMethods(filter, this.environment, this.resourceLoader, this.registry); typeFilters.add(filter); break; default: throw new IllegalArgumentException("Filter type not supported with Class value:" + filterType); } } for (String expression : filterAttributes.getStringArray("pattern")) {switch (filterType) { case ASPECTJ: typeFilters.add(new AspectJTypeFilter(expression, this.resourceLoader.getClassLoader())); break; case REGEX: typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression))); break; default: throw new IllegalArgumentException("Filter type not supported with String pattern:" + filterType); } } return typeFilters; }
ComponentScanAnnotationParser
的 parse 方法中,scanner 最后为什么又加了一个AbstractTypeHierarchyTraversingFilter
呢?我们看一下它的 match 方法,发现是 过滤掉启动类,不让它作为 @configuration 标记的候选类,避免再一次解析启动类上的各种注解(因为它的两个参数 considerInherited 和 considerInterfaces 在 scanner.addExcludeFilter 这条语句中,设置成了 false,导致下面的判断语句不生效)。public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { ... ClassMetadata metadata = metadataReader.getClassMetadata(); if (matchClassName(metadata.getClassName())) {return true;} if (this.considerInherited) {...} if (this.considerInterfaces) {...} return false; }
注:启动类本身还是会注入到 spring 的 bean 池中的,具体见
SpringApplication
的 load 方法 -
ExcludeFilter 在
ClassPathScanningCandidateComponentProvider
的 isCandidateComponent 方法中被使用。protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {for (TypeFilter tf : this.excludeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return false;} } for (TypeFilter tf : this.includeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return isConditionMatch(metadataReader); } } return false; }
-
AutoConfigurationExcludeFilter
的作用是过滤掉会自动配置的配置类,避免重复@Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 如果这个类被 @Configuration 标注,且属于自动加载的配置,那么过滤它,避免重复 return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader); } private boolean isConfiguration(MetadataReader metadataReader) {return metadataReader.getAnnotationMetadata() .isAnnotated(Configuration.class.getName()); } private boolean isAutoConfiguration(MetadataReader metadataReader) {return getAutoConfigurations() .contains(metadataReader.getClassMetadata().getClassName()); } protected List<String> getAutoConfigurations() {if (this.autoConfigurations == null) { /** 从 META-INF/spring.factories 文件中,找出 EnableAutoConfiguration.class 多个 jar 包中,都存在 spring.factories 文件 其中包含 EnableAutoConfiguration.class 的 spring.factories 文件,位于 spring-boot-autoconfigure **/ this.autoConfigurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, this.beanClassLoader); } return this.autoConfigurations; }
-
TypeExcludeFilter
的作用是加载 spring bean 池中所有针对 TypeExcludeFilter 的扩展,并循环遍历这些扩展类调用其 match 方法public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) { // 加载 spring bean 池中所有针对 TypeExcludeFilter 的拓展 Collection<TypeExcludeFilter> delegates = ((ListableBeanFactory) this.beanFactory) .getBeansOfType(TypeExcludeFilter.class).values(); // 循环遍历,调用其 match 方法 for (TypeExcludeFilter delegate : delegates) {if (delegate.match(metadataReader, metadataReaderFactory)) {return true;} } } return false; }