Springboot热部署原理

一、配置加载

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(SampleTomcatApplication.class, args);
        String foo = ctx.getEnvironment().getProperty("foo");
        System.out.println(foo);
    }

打印结果

aaa,bbb

源码解析

1、我们在idea环境配置的参数Program arguments上配置的参数,就会被传进main方法的args中

    //封装命令行参数
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    
    public DefaultApplicationArguments(String... args) {
        Assert.notNull(args, "Args must not be null");
        this.source = new Source(args);
        this.args = args;
    }
    Source(String[] args) {
        super(args);
    }
    public SimpleCommandLinePropertySource(String... args) {
        super(new SimpleCommandLineArgsParser().parse(args));
    }
    //解析命令行参数
    public CommandLineArgs parse(String... args) {
        CommandLineArgs commandLineArgs = new CommandLineArgs();
        for (String arg : args) {
            //固定格式
            if (arg.startsWith("--")) {
                String optionText = arg.substring(2);
                String optionName;
                String optionValue = null;
                int indexOfEqualsSign = optionText.indexOf('=');
                if (indexOfEqualsSign > -1) {
                    optionName = optionText.substring(0, indexOfEqualsSign);
                    optionValue = optionText.substring(indexOfEqualsSign + 1);
                }
                else {
                    optionName = optionText;
                }
                if (optionName.isEmpty()) {
                    throw new IllegalArgumentException("Invalid argument syntax: " + arg);
                }
                commandLineArgs.addOptionArg(optionName, optionValue);
            }
            else {
                commandLineArgs.addNonOptionArg(arg);
            }
        }
        return commandLineArgs;
    }

解析完命令行参数,最终放入到了PropertySource的source属性中,代码就不放了

2、构建环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        //创建并配置相应的环境,获取对应的ConfigurableEnvironment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        //根据用户配置,配置 environment系统环境
        configureEnvironment(environment, applicationArguments.getSourceArgs());

创建环境

//根据环境创建对应ConfigurableEnvironment
    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
        case SERVLET://Web程序
            return new StandardServletEnvironment();
        case REACTIVE://响应式web环境
            return new StandardReactiveWebEnvironment();
        default://普通程序
            return new StandardEnvironment();
        }
    }

都继承自AbstractEnvironment

public abstract class AbstractEnvironment implements ConfigurableEnvironment {
    
    //初始化配置文件source对象
    private final MutablePropertySources propertySources = new MutablePropertySources();
    
    //初始化了配置文件解析器
    private final ConfigurablePropertyResolver propertyResolver =
            new PropertySourcesPropertyResolver(this.propertySources);

    ···
}

解析配置文件,并配置到环境中

    protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            ConversionService conversionService = ApplicationConversionService.getSharedInstance();
            environment.setConversionService((ConfigurableConversionService) conversionService);
        }
        // 将main 函数的args封装成 SimpleCommandLinePropertySource 加入environment中。
        configurePropertySources(environment, args);
        // 激活相应的配置文件
        configureProfiles(environment, args);
    }
    
    protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
        MutablePropertySources sources = environment.getPropertySources();
        if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
            sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
        }
        if (this.addCommandLineProperties && args.length > 0) {
            String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
            if (sources.contains(name)) {
                PropertySource<?> source = sources.get(name);
                CompositePropertySource composite = new CompositePropertySource(name);
                //解析args,并设置到source属性中,SimpleCommandLinePropertySource继承自PropertySource
                composite.addPropertySource(
                        new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
                composite.addPropertySource(source);
                //存在覆盖的参数,则替换
                sources.replace(name, composite);
            } else {
                //解析并设置参数到环境中
                sources.addFirst(new SimpleCommandLinePropertySource(args));
            }
        }
    }

获取配置文件属性String foo = ctx.getEnvironment().getProperty("foo");

    public String getProperty(String key) {
        return this.propertyResolver.getProperty(key);
    }

走的就是AbstractEnvironment方法,通过ConfigurablePropertyResolver的方法获取,具体获取源码也不看了。

二、热部署

jar包依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

原文地址:https://www.cnblogs.com/sglx/p/15673243.html