Springboot源码学习——框架的启动流程

Springboot源码学习——框架的启动流程

Scroll Down

框架的启动流程

1.整体流程

框架初始化 ----->启动框架 ----->框架自动化装配

1.框架初始化

配置资源加载器
配置primarySource
应用环境监测
配置系统初始化器
配置应用监听器
配置main方法所在类

2.启动框架

计时器开始计时----->headlessmos赋值----->发送applicationStartingEvent----->配置环境模块----->发送applicationEnviromentPreparedEvent----->打印banner----->创建应用上下文----->初始化失败分析器----->关联springboot组件与应用上下文----->发送applicationContentextInitalizedEvent----->加载source到contenxt----->发送applicationPreparedEvent----->刷新上下文----->计时器停止计时----->发送applicationStartedEvent----->调用框架启动扩展类----->发送applicationReadyEvent

3.框架自动化装配

收集配置文件中的配置工厂类----->加载组件工厂----->注册组件内自定义bean

2.系统初始化器

ApplicationContenxtInitializer
定义:spring容器刷新之前执行的一个回调接口,可以向spring添加我们自定属性
作用:向springboot容器注册属性
使用:继承接口自定义实现

1.实现方式一

实现ApplicationContenxtInitializer接口,配置spring.factories填写实现的类


import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: MyInitializer
 * @Description: 自定义系统初始化容器
 * @author: XP
 * @data: 2020/3/6
 */
@Order(1)
public class MyInitializer implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        //拿到运行环境
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        //存入我们需要的东西
        Map<String,Object> map = new HashMap<>(1);
        map.put("key","lets go");
        //去拿一个容器 装我们的东西
        MapPropertySource mapPropertySource=new MapPropertySource("myInitializerMap",map);
        //加入到运行环境中
        environment.getPropertySources().addLast(mapPropertySource);
        System.err.println("执行了我们的初始化方法");
    }
}

image.png

org.springframework.context.ApplicationContextInitializer=life.xp.bootdemo.initializer.MyInitializer

获取方式:


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @ClassName: TestInitlazierService
 * @Description: 
 * @author: XP
 */
@Component
public class TestInitlazierService implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
    public String getInitlazier(String key){
        return applicationContext.getEnvironment().getProperty(key);
    }
}

2.实现方式二

实现ApplicationContenxtInitializer接口,将SpringApplication类初始化设置进去


import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: MyInitializer
 * @Description: 自定义系统初始化容器
 * @author: XP
 */
@Order(2)
public class MyInitializer2 implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        //拿到运行环境
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        //存入我们需要的东西
        Map<String,Object> map = new HashMap<>(1);
        map.put("key2","lets go 222");
        //去拿一个容器 装我们的东西
        MapPropertySource mapPropertySource=new MapPropertySource("myInitializerMap",map);
        //加入到运行环境中
        environment.getPropertySources().addLast(mapPropertySource);
        System.err.println("执行了我们的初始化方法22222");
    }
}

@SpringBootApplication
@MapperScan("life.xp.bootdemo")
public class BootdemoApplication {

    public static void main(String[] args) {

//        SpringApplication.run(BootdemoApplication.class, args);
        SpringApplication springApplication=new SpringApplication(BootdemoApplication.class);
        springApplication.addInitializers(new MyInitializer2());
        springApplication.run(args);
    }

}

3.实现方式三

实现ApplicationContenxtInitializer接口,在application.properties填写接口实现,会优先于其他实现方式


import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: MyInitializer
 * @Description: 自定义系统初始化容器
 * @author: XP
 * @data: 2020/3/6
 */
@Order(3)
public class MyInitializer3 implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        //拿到运行环境
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        //存入我们需要的东西
        Map<String,Object> map = new HashMap<>(1);
        map.put("key3","lets go 333");
        //去拿一个容器 装我们的东西
        MapPropertySource mapPropertySource=new MapPropertySource("myInitializerMap",map);
        //加入到运行环境中
        environment.getPropertySources().addLast(mapPropertySource);
        System.err.println("执行了我们的初始化方法3333");
    }
}

application.properties:

context.initializer.classes: life.xp.bootdemo.initializer.MyInitializer3

2.系统初始化器的加载

1.通过spring.factories

2.硬编码的方式加入

3.通过application.properties

springFactoriesLoader
定义:框架内部使用的通用工厂加载机制,识别系统初始化器
作用:从classpath下多个jar包指定的位置读取文件并初始化类
读取文件形式:文件内容必须是key-values 即properties类型,key是全限定名,多个用,分隔

3.系统监听器

springboot基于事件驱动,事件驱动离不开对应的监听器

1.自定义事件监听

1.事件

事件:


/**
 * @ClassName: CookEvent
 * @Description: 做饭事件
 * @author: XP
 */
public abstract class CookEvent {
    public abstract String getCook();
}

对应实现类


/**
 * @ClassName: MeatEvent
 * @Description: 做肉吃事件
 * @author: XP
 */
public class MeatEvent extends CookEvent {
    @Override
    public String getCook() {
        return "做肉吃事件";
    }
}


/**
 * @ClassName: VegetableEvent
 * @Description: 做菜吃
 * @author: XP
 */
public class VegetableEvent extends CookEvent {
    @Override
    public String getCook() {
        return "做菜吃事件";
    }
}

2.监听器

/**
 * @Author xp
 * @Description 做饭监听器
 * @Param
 * @return
 **/
public interface CookListener {
    void listenCook(CookEvent cookEvent);
}

对应实现


/**
 * @ClassName: MeatListener
 * @Description: 吃肉的监听器
 * @author: XP
 */
public class MeatListener implements CookListener {
    @Override
    public void listenCook(CookEvent cookEvent) {
        if(cookEvent instanceof MeatEvent){

            System.out.println("吃肉了"+cookEvent.getCook());
        }
    }
}


/**
 * @Author xp
 * @Description 吃菜的监听器
 * @Param
 * @return
 **/
public class VegetableListener implements CookListener{
    @Override
    public void listenCook(CookEvent cookEvent) {
        if(cookEvent instanceof VegetableEvent){

            System.out.println("吃菜了"+cookEvent.getCook());
        }
    }
}

3.事件广播


import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: AbstractBroadcastEvent
 * @Description:
 * @author: XP
 */
public abstract class AbstractBroadcastEvent implements BroadcastEvent {
    List<CookListener> cookListenerList=new ArrayList<>();
    @Override
    public void broadCastEvent(CookEvent cookEvent) {
        toStart();
        cookListenerList.forEach(e->e.listenCook(cookEvent));
        toEnd();
    }

    public abstract void toStart();
    public abstract void toEnd();

    @Override
    public void addListener(CookListener cookListener) {
        cookListenerList.add(cookListener);
    }

    @Override
    public void removeListener(CookListener cookListener) {
        cookListenerList.remove(cookListener);
    }

}


/**
 * @Author xp
 * @Description 事件广播
 * @Param
 * @return
 **/
public interface BroadcastEvent {
    void broadCastEvent(CookEvent cookEvent);
    void addListener(CookListener cookListener );
    void removeListener(CookListener cookListener);
}


/**
 * @ClassName: CookBroadcastEvent
 * @Description: 做饭广播事件
 * @author: XP
 */
public class CookBroadcastEvent extends AbstractBroadcastEvent {
    @Override
    public void toStart() {
        System.out.println("开始做饭");
    }

    @Override
    public void toEnd() {
        System.out.println("结束做饭");
    }
}

4.测试


/**
 * @ClassName: TestListener
 * @Description:
 * @author: XP
 */
public class TestListener {
    public static void main(String[] args) {
        AbstractBroadcastEvent abstractBroadcastEvent=new CookBroadcastEvent();
        CookListener cookListener=new MeatListener();
        CookListener vegetableListener=new VegetableListener();
        abstractBroadcastEvent.addListener(cookListener);
        abstractBroadcastEvent.addListener(vegetableListener);
        CookEvent meatEvent=new MeatEvent();
        abstractBroadcastEvent.broadCastEvent(meatEvent);
    }
}

springboot是使用自动装配的方式注入
image.png
我们可以定义一个运行的类 其他的listener使用自动注入的方式,将类的关系交给spring去管理和装配,降低耦合度:

@Component
public class CookRunListener {
    @Autowired
    private AbstractBroadcastEvent abstractBroadcastEvent;

    public void CookMeatEvent(){
        abstractBroadcastEvent.broadCastEvent(new MeatEvent());
    }

    public void CookVegetableEvent(){
        abstractBroadcastEvent.broadCastEvent(new VegetableEvent());
    }
}

image.png

2.springboot的事件监听

1.类关系

事件监听器的加载方式如同系统初始化话化器也是同样的三种方式加载
image.png

2.事件发送顺序

框架启动(事件):
starting(框架启动就发出)---->environmentPrepared(环境准备事件,启动属性和我们指定事件)---->contextInitialized(上下文初始化)---->prepared(上下文已经准备好)---->started(bean实例化完成)---->ready---->启动完毕
如果失败
failed

3.监听器注册方式

以starting事件为例:
image.png
将对starting事件感兴趣的监听器以线程调度的方式进行运行
image.png
image.png
先从缓存中寻找是否有事件对应的监听器列表,没有的话就要根据事件的类型和监听器指定的监听事件进行判断是否加入运行的列表
image.png
image.png
image.png
image.png