• SpringBoot自动装配原理


    日期: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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //在新建一个类实现ImportSelector
    public class MySpringbootTest implements ImportSelector {
    //重写selectImports
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            return new String[]{"com.example.test.person"};//Person的全限定名
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    //在启动类中加入@Import()
    @SpringBootApplication
    @Import(MySpringbootTest.class)
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    //测试
    @SpringBootTest
    public class ImportTest {
    
        @Autowired
        private person p;
    
        @Test
        public void test1(){
            System.out.println(p);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述
    可以看到我这里没有加任何包扫描注解,但是确能实例化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这个类。
  • 相关阅读:
    数字化时代,重新思考IT运维价值
    2022-11-07 Excel的函数使用
    又是一年开学季,老学长告诉你弯道超车的法则
    Python+Qt多点最短路径(最优路径)算法实现
    PyTorch显存机制分析
    XP系统快捷方式故障
    为什么定时发朋友圈会更有效呢?
    煤矿皮带跑偏监测识别系统
    将对象与返回的数据所对应的键相同时一一赋值
    Jetpack Compose中的state核心思想
  • 原文地址:https://blog.csdn.net/weixin_44233087/article/details/126486327