Spring Bean的自动装配(SPI机制)(二)

1,782 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

理解SPI机制

SPI机制:

Service Provider Interface,就是一种服务发现的机制

举个例子: 以前:我是甲方调用你乙方的接口,乙方给我接口,然后提供给我接口文档,我按照文档进行开发

现在有了SPI机制:甲方自己提供接口,我仅仅只是提供接口,不实现,我提供api,乙方根据我这个api,自己去实现,然后乙方把jar给甲方,甲方只要找到依赖就行

调用逻辑:

1,甲方提供接口

2,乙方依赖接口所在的包,并且创建实现类实现该接口

3,在乙方实现类所在的jar包里面你要告诉甲方,实现类到底在哪里

在META-INF目录下创建一个services目录,在services目录下以接口的全路径名作为文件名,然后在文件里面写上所有实现类的全路径名

4,甲方依赖你乙方的jar包之后要进行调用ServiceLoader.load(SPIService.class)

image-20220929215419153

image-20220929215523825

load底层是一个迭代器

image-20220929220218439

迭代:

image-20220929220235892

核心代码:

image-20220929220353154

这里就很明显了,这个PREFIX就是**META-INF/services/**

image-20220929220530663

再利用反射机制,再实例化一下

image-20220929220754690

image-20220929221442004

SPI机制在SpringBoot中的体现

总结就是:

springboot启动,执行main方法里的run方法------>

扫描@SpringBootApplication这个注解,这个注解里带了个@Import注解------>

import注解里面有AutoConfigurationImportSelector类------>

这个类实现了DeferredImportSelector接口,DeferredImportSelector接口又实现了ImportSelector接口------>

这个接口里有个SelectImport方法,这个方法实现了配置类的寻找------>

寻找的过程实际上就是SpringBoot的SPI机制,去META-INF/spring.factories文件

上面的SPI样例里的ServiceLoader,到SpringBoot中就是SpringFactoryLoader

image-20220930141807476

点进去就可以看到

image-20220930142441595

也写死了

image-20220930142852970

SpringBoot中的Spring

首先springboot是包含spring的

springboot的run方法里面有个refreshContext方法是spring的主要方法,这个方法就是spring,spring的所有流程都在这个方法里面(这个方法其他的东西是springboot的东西)

image-20220930150450633

refresh方法的源码:

spring 最重要的12步

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        //1
        this.prepareRefresh();
        //2
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        //3
        this.prepareBeanFactory(beanFactory);
​
        try {
            //4
            this.postProcessBeanFactory(beanFactory);
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            //5
            this.invokeBeanFactoryPostProcessors(beanFactory);
            //6
            this.registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();
            //7
            this.initMessageSource();
            //8
            this.initApplicationEventMulticaster();
            //9
            this.onRefresh();
            //10
            this.registerListeners();
            //11
            this.finishBeanFactoryInitialization(beanFactory);
            //12
            this.finishRefresh();
        } catch (BeansException var10) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
            }
​
            this.destroyBeans();
            this.cancelRefresh(var10);
            throw var10;
        } finally {
            this.resetCommonCaches();
            contextRefresh.end();
        }
​
    }
}

spring:

1.将类注册成BeanDefinition

两种方法:

1)xml文件,读然后解析,实现方法是obtain

ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

2)注解

this.invokeBeanFactoryPostProcessors(beanFactory);

2.然后实例化

image-20220930154541022

流程图:

image-20220930151910449

spring spi和jdk spi的区别

image-20220930155359507

springboot的多了个自动装配的key = EnableAutoConfiguration

补充:

Dubbo的spi最最最重要的区别就是用谁加载谁

四种方法,是先加载到容器中,然后用哪个实例化哪个