Spring Boot 的启动类上标注 @SpringBootApplication 注解 , 其默认扫描包就是启动类所在的包 .
为什么是这样? 我们看看 @SpringBootApplication 注解的定义
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
......
}
@SpringBootApplication 上的注解 @ComponentScan 根本就没有定义要扫描的包的名称 , Spring 在解析时, 将直接或间接标注@ComponentScan 注解的类所在包作为默认的扫描包 .
一个类使用了@SpringBootApplication来标注 , 就是间接标注了@ComponentScan .
为了验证上面的描述 , 我们看看需要看看源码 , 如何找到对应的源码呢? 这要求大家有一些源码的知识储备 , 需要知道Spring是在哪里解析配置类的 !
其实就是在调用后置处理器的阶段 , 调用后置处理器 ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry 方法来解析的 ,我们在该方法中打上断点 , 一路跟踪 (这过程需要对源码又一定的了解 ,第一次追踪会比较耗时) , 调用栈如下:
//为了美观 , 我们将org.springframework 替换为 o.s
parse:126, ComponentScanAnnotationParser (o.s.context.annotation)
doProcessConfigurationClass:287, ConfigurationClassParser (o.s.context.annotation)
processConfigurationClass:245, ConfigurationClassParser (o.s.context.annotation)
parse:198, ConfigurationClassParser (o.s.context.annotation)
parse:167, ConfigurationClassParser (o.s.context.annotation)
processConfigBeanDefinitions:308, ConfigurationClassPostProcessor (o.s.context.annotation)
postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (o.s.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (o.s.context.support)
invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (o.s.context.support)
invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (o.s.context.support)
refresh:525, AbstractApplicationContext (o.s.context.support)
refresh:122, EmbeddedWebApplicationContext (o.s.boot.context.embedded)
refresh:693, SpringApplication (o.s.boot)
refreshContext:360, SpringApplication (o.s.boot)
run:303, SpringApplication (o.s.boot)
run:1118, SpringApplication (o.s.boot)
run:1107, SpringApplication (o.s.boot)
main:14, HelloSpringBootApplication (com.yh.stu.springboot)
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
Assert.state(this.environment != null, "Environment must not be null");
Assert.state(this.resourceLoader != null, "ResourceLoader must not be null");
// 略......
if (basePackages.isEmpty()) {
// 获取 declaringClass 的包名
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
// 扫描 basePackages指定的包
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
这里的 declaringClass 就是我们的启动类