首先要了解springboot启动原理,我们需要先引出两个问题:
-
我们没有在启动类上加ComponetScan注解,(我们都知道这个注解的作用是为了扫描指定包下的所有类并且将这些类反射创建对象加载到springioc容器中)
那我们没有写这个注解,为什么还是可以扫描到我们写的类呢? -
我们没有将第三方的类注册成为bean对象,那为什么会生效呢?
研究启动原理问题需求研究启动类的一个注解——@SpringBootApplication
点进去@SpringBootApplication注解,我们可以看到此注解包括四个原生注解,以及三个需要特殊关注的注解。(原生注解在此不过多解释)
我们可以看到,第一个需要特殊关注的注解中有一个@SpringBootConfiguration
,点进去这个注解我们可以看到,除了原生注解以外,有一个Configuration注解,这就表明了,我们的启动类也是一个配置类,可以当作配置类使用,我们可以将一些第三方类在启动类中注册成为bean对象
返回上层,我们看第二个需要特殊关注的注解—@CompoentScan
注解,这就表明了,springboot帮我们写了这个注解,所以我们包下的所有类加了注解都会被扫描到。那又引出了一个问题——包名从何而来?
我们继续看第三个需要特殊关注的注解——@EnableAutoConfiguration
,顾名思义 启动自动装配,这个注解就是自动装配注解
。
点进去这个注解,我们可以看到,除了原生注解外,还有两个需要关注的注解:①AutoConfigurationPackage、② Import({AutoConfigurationImportSelector.class})
① AutoConfigurationPackage:点进去这个注解,我们可以看到他Import,导入了一个Registrar类,点进去这个类可以看到,他获取了启动类的包名。我们也可以通过打断点运行看到,他果然是获取了启动类所在的包名。那就证明了,我们的@ComponetScan所需要的包名就是这个注解提供的,也就证明了我们自己写的类可以加载到的原因。
② Import({AutoConfigurationImportSelector.class}):我们继续看这个注解,他导入了AutoConfigurationImportSelector这个类。
点进去这个类,我们就可以看到,有一个configurations集合,这里还用到了断言的方式。
他断言这个集合不是空的,如果是空的就会打印这么一段话:在META-INF/spring.factories中没有找到自动配置类。如果你都是使用自定义包装,请确保文件正确。
那我们就可以知道了,这个类会加载META-INF包下的spring.factories文件。
META-INF包是用来配置应用程序、扩展程序、类加载器和服务manifest.mf文件,在用jar打包时自动生成。当我们在pom文件中引入依赖时,在引入的第三方jar包中就会存在META-INF包,此包下就会存在spring.factories文件。springboot会加载所有jar包下的META-INF包下的spring.factories文件。然后读取这个键对应的所有值:org.springframework.boot.autoconfigure.EnableAutoConfiguration,这些值都是全限定类名,里面就包括比如说dispatcherservlet前端控制器等等。点进去这些类,我们就可以看到,他们都有注册bean对象。这就证明了我们的那些第三方类库是如何加载的了!
条件装配
:通过每个全限定类名点进去,我们可以看到,每个类上都有以下其中一个注解。也就意味着我们的项目中需要真正的有这个类,他才会被加载到并且实现自动装配,并不是每次启动都会加载很多类。所以当我们需要springboot帮我们自动装配一些第三方类的时候,只需要在pom文件中加依赖、在yam中加配置文件,他就会帮我们去实现自动装配。
并不是读取META-INF/spring.factories所有的Bean都会被初始化,在配置类中使用@Condition来加载满足条件的Bean
- ConditionalOnClass: 判断环境中是否有对应字节码文件才初始化Bean
- ConditionalOnProperty: 判断配置文件中是否有对应属性和值才初始化Bean
- ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean