日期:2022年8月23日
我们可以按住Shift+鼠标右键,进入查看@SpringBootApplication
其中:
@Target({ElementType.TYPE}) (用来规定下面这个注解的使用位置)表明这个注解要加到类上。
@Retention(RetentionPolicy.RUNTIME)(用来规定下面这个注解的存活时间)表明可以存活在运行时。
@Inherited:表明这个类的子类也可以继承该注解
@Documented :( 具体效果演示)是 java 在生成文档,是否显示注解的开关
//核心注解
@SpringBootConfiguration :表明当前类是一个SpirngBoot配置类
@EnableAutoConfiguration:表明该类支持自动装配
@ComponentScan:需要扫描的包(但这里看不出来都扫描哪个包,往下看)
查看@EnableAutoConfiguration
点开@EnableAutoConfiguration注解如下:
@AutoConfigurationPackage:指定需要扫描配置的包,就是springboot启动类所在的包。
@Import({AutoConfigurationImportSelector.class}):导入AutoConfigurationImportSelector这个配置类.加载自动配置的类。
查看@AutoConfigurationPackage
里面会有一个@Import({Registrar.class}) 它的作用是导入 Registrar这个类
我们可以debug,看一下这个类的作用
如图我们可以看到这个类的一个作用是查看当前项目的启动类所处的包。
查看@Import({AutoConfigurationImportSelector.class})
我们进入AutoConfigurationImportSelector类:
其中这个类实现了DeferredImportSelector类,
并且DeferredImportSelector也实现了ImportSelector
那在ImportSelector这个类有一个方法,
String[] selectImports(AnnotationMetadata var1);
这个方法的的作用是将此方法的返回值都加载到spring容器中。
//例子
//我们新建一个Person类
public class person {
private String name;
private int age;
}
//在新建一个类实现ImportSelector
public class MySpringbootTest implements ImportSelector {
//重写selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.example.test.person"};//Person的全限定名
}
}
//在启动类中加入@Import()
@SpringBootApplication
@Import(MySpringbootTest.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
//测试
@SpringBootTest
public class ImportTest {
@Autowired
private person p;
@Test
public void test1(){
System.out.println(p);
}
}
可以看到我这里没有加任何包扫描注解,但是确能实例化Person。
我们回到AutoConfigurationImportSelector类,在这个类中有一个核心方法getAutoConfigurationEntry:
在这个方法中调用了getCandidateConfigurations(annotationMetadata, attributes)方法,这个方法的作用是把类作为key:org.springframework.boot.autoconfigure.EnableAutoConfiguration
加载META-INF/spring.factories中所有的key对应的value值。
我们可以按两下 shift 查看一下spring.factories
点进去就可以看到:
回到 class AutoConfigurationImportSelector ,他就可以接收到这些配置信息
那么再回到@interface SpringBootApplication
我们点击@ComponentScan的AutoConfigurationExcludeFilter.class
看到这里我们就可以知道了,@ComponentScan都扫描了哪些包
总结流程:
我们进入@SprignbootApplication这个注解中,里面会有四类注解
其中:
1.元注解包括@Target(声明当前注解的使用位置),@Retention(声明这个注解的生命周期)
@Document(用来显示在doc在显示注解信息),@Inherited(用来标记子类是否继承该注解)。2.@SpringBootConfiguration(用来标记这是一个springboot配置类)。
3.@EnableAutoConfiguration(核心注解,用来实现springboot自动装配)
4.@ComponentScan(包扫描),这个注解大家都熟悉,但是我们可以看到它并没有明确写出他需要扫面哪些包,但是在括号里面我们可以看到,有两个@filter ,其中在第二filter中,他会加载AutoConfiguration.class这个类,那在这个类中,有一个getAutoConfiguration方法,他会通过Spring工厂加载去加载@interface EnableAutoConfiguration,这个注解,那在@EnableAutoConfiguration中,有三类注解:
A:元注解(自己去看)
B:@AutoConfigurationPackage,在这个注解里面也有一个注解@Import, 这个注解是为将符合条件的bean加载到Ioc容器中,那这里是引入的Registrar.class这个类,在这个类中有一个方法:getRegistrarBeanDefinition(AnnotationMetadata metadata, BeanDefinitionRegistry registry),那这个方法的作用其实就是得到当前启动类的包路径。
C:@Import(AutoConfigurtionImportSelector.class),这个注解是为了加载AutoConfigurtionImportSelector这个类,那在这个类中有三个核心方法,其中:
- a:通过重写ImportSelector接口中的方法selectImports,这个方法的作用是为了将需要的类,加载到Spring容其中。
- b:getCandidateConfiguration(AnnotationMetadata metadata, AnnotationAttributes attributes),这个方法的作用通过SpringFactoriesLoader去加载,以key=value的方式去读取在每个jar包中META-INF/spring.factories 中Sprongboot帮我们配置好的配置类路径。
- c:然后在getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata)中去调用b的方法,对得到的list进行包括去重、检查是否有排除的等操作后赋值给 configurations 集合。然后将参数传给AutoConfigurationEntry这个类。