背景

        SpringBootApplication里面的注解都是什么意思?我们只需要运行run方法就能把整个项目跑起来,我们controller,service层的注解是怎么扫描到的,以及spring给我们提供的各个bean对象都是怎么加载进来的。

源码解析

        点击SpringBootApplication注解,注解由下面这些注解修饰。

springboot 注解 这个接口即将废弃 springbootapplication注解原理_System

2.1 @Target(ElementType.TYPE) 

springboot 注解 这个接口即将废弃 springbootapplication注解原理_mybatis_02

 //这个注解的主要意思是SpringBootApplication注解可以修饰类,接口(包括注解),枚举。

2.2@Retention(RetentionPolicy.RUNTIME)

springboot 注解 这个接口即将废弃 springbootapplication注解原理_System_03

//指定注解的保留时间为整个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);
        }
    }
}



springboot 注解 这个接口即将废弃 springbootapplication注解原理_spring_04

项目成功启动。

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

        

springboot 注解 这个接口即将废弃 springbootapplication注解原理_spring_05

主要关注最后两个注解。

 @import注解会将某个指定的类放入到容器中来,有其他更高级的用法需要额外研究。

2.5.1 AutoConfigurationPackage

springboot 注解 这个接口即将废弃 springbootapplication注解原理_java_06

这个类会将指定package下的类批量注册到容器中来

 方法会返回启动类所在的包路径。这也是我们自定义的bean对象不能乱放的原因。

new PackageImports(metadata).getPackageNames().toArray(new String[0])

2.5.2 @Import(AutoConfigurationImportSelector.class)

        引入AutoConfigurationImportSelector到容器中来。debug的时候会发现先调用这个类的process()方法。

springboot 注解 这个接口即将废弃 springbootapplication注解原理_System_07

         需要自动导入什么类,在 getCandidateConfigurations(annotationMetadata, attributes)下面返回。

springboot 注解 这个接口即将废弃 springbootapplication注解原理_System_08

 springBoot提供了133个适应不同场景的自动配置类。

springboot 注解 这个接口即将废弃 springbootapplication注解原理_spring_09

        
         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

    

springboot 注解 这个接口即将废弃 springbootapplication注解原理_spring_10

        并不是所有扫描到的都会加载到容器中。@ConditionalOnClass({ Bucket.class, CouchbaseRepository.class })。某些类存在才会把这个类加载到容器中,也就是得把相关maven依赖导入配置才会生效。

springboot 注解 这个接口即将废弃 springbootapplication注解原理_加载_11

 来实验一下。

当前CouchbaseAutoConfiguration这个配置类的条件注解类不存在。

springboot 注解 这个接口即将废弃 springbootapplication注解原理_System_12

 把容器里面所有的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 注解 这个接口即将废弃 springbootapplication注解原理_java_13

 可以利用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的依赖放入到我们项目的依赖中。

springboot 注解 这个接口即将废弃 springbootapplication注解原理_System_14

 hbase相关bean已经加载到容器中。

springboot 注解 这个接口即将废弃 springbootapplication注解原理_java_15

2.6 @ComponentScan


    等同于ComponentScan(当前类所在的包路径),并且排除掉

{ @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }

这两个部分。