背景
SpringBootApplication里面的注解都是什么意思?我们只需要运行run方法就能把整个项目跑起来,我们controller,service层的注解是怎么扫描到的,以及spring给我们提供的各个bean对象都是怎么加载进来的。
源码解析
点击SpringBootApplication注解,注解由下面这些注解修饰。
2.1 @Target(ElementType.TYPE)
//这个注解的主要意思是SpringBootApplication注解可以修饰类,接口(包括注解),枚举。
2.2@Retention(RetentionPolicy.RUNTIME)
//指定注解的保留时间为整个JVM运行周期
2.3 @Documented
//跟生成API文档有关
2.3 @Inherited
//Inherited就是继承的意思,使用这个注解修饰的注解具有继承性。比如创建一个类继承我们的启动类,子类里面不加@SpringBootApplication注解也能把项目跑起来。
public class InheritedSpringgoApplication extends SpringgoApplication{
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(InheritedSpringgoApplication.class, args);
//获取所有的bean对象
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
项目成功启动。
2.4 @SpringBootConfiguration
派生于@Configuration,相当于配置类的功能。
/**
* 1、配置类里面使用@bean标注的方法上给容器注册组件,默认也是单实例的
* 2、配置类本身也是组件
* 3、proxyBeanMethods: 代理bean的方法
*/
@Configuration(proxyBeanMethods = true) //spring的配置类,相当于以前的xml文件
public class MyConfig {
/**
* 如果bean不指定名称,就以方法名称作为beanId,Bean的类型就是返回类型,Bean的值就是返回值
* ConditionalOnBean 某个bean存在才进行创建
* @return
*/
@Bean("zhangsan")
@ConditionalOnBean(MyConfig.class)
public User getUser() {
return new User("zhangsan",132,null);
}
public Pet getPet() {
return new Pet(13,"dahuang");
}
}
2.5 @EnableAutoConfiguration
主要关注最后两个注解。
@import注解会将某个指定的类放入到容器中来,有其他更高级的用法需要额外研究。
2.5.1 AutoConfigurationPackage
这个类会将指定package下的类批量注册到容器中来
方法会返回启动类所在的包路径。这也是我们自定义的bean对象不能乱放的原因。
new PackageImports(metadata).getPackageNames().toArray(new String[0])
2.5.2 @Import(AutoConfigurationImportSelector.class)
引入AutoConfigurationImportSelector到容器中来。debug的时候会发现先调用这个类的process()方法。
需要自动导入什么类,在 getCandidateConfigurations(annotationMetadata, attributes)下面返回。
springBoot提供了133个适应不同场景的自动配置类。
Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);在这里由指定位置扫描类信息。
从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
并不是所有扫描到的都会加载到容器中。@ConditionalOnClass({ Bucket.class, CouchbaseRepository.class })。某些类存在才会把这个类加载到容器中,也就是得把相关maven依赖导入配置才会生效。
来实验一下。
当前CouchbaseAutoConfiguration这个配置类的条件注解类不存在。
把容器里面所有的bean对象打印出来。
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(InheritedSpringgoApplication.class, args);
//获取所有的bean对象
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
hbase相关bean不存在
可以利用springBoot的插件管理特性在maven中找到相关依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.4</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
<version>2.6.4</version>
</dependency>
找到带有starter的依赖放入到我们项目的依赖中。
hbase相关bean已经加载到容器中。
2.6 @ComponentScan
等同于ComponentScan(当前类所在的包路径),并且排除掉
{ @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }
这两个部分。