springboot启动流程

1、启动流程

springboot流程
    1、env环境变量
        在application.yml中配置的解析成变量
        自定义配置文件(@PropertySource标记如manager-config-dev.yml)中的会解析成bean
    2、BeanFactoryPostProcessor 可修改bean定义
    3、BeanPostProcessor 可修改bean实例
    4、bean生命周期
        构造函数
        ->@PostConstruct
        ->InitializingBean
        ->(所有单例bean都初始化完成以后)SmartInitializingSingleton
        ->ApplicationRunner(容器启动后)
        ->CommandLineRunner
        ->@PreDestroy
        ->DisposableBean
    5、回调接口Aware

ConfigurationClassParser解析顺序:
@Component(@Service、@Repository、@Configuration) -> @PropertySource -> @ComponentScan -> @Import -> @ImportResource -> @Bean

2、代码调试

配置文件
application.yml

spring:
  profiles:
    active: dev

xss:
  enabled: true
  excludePaths:
    - /*
    - /*


manager-config-dev.yml

manager-config:
  url: https://www.baidu.com
  map:
    k1: v1
    k2: v2
配置文件META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=org.pp.spring.MyApplicationContextInitializer
org.springframework.boot.env.EnvironmentPostProcessor=org.pp.spring.env.MyEnvironmentPostProcessor
属性配置
@Configuration
@ConfigurationProperties(prefix = "xss")
@Data
public class XssFilterProperties {
    /* 是否启用xss过滤器 */
    private boolean enable = true;
    /* 排除过滤的url */
    private List<String> excludePaths;
}

@Configuration
@ConfigurationProperties(prefix = "manager-config")
@PropertySource(value = "classpath:manager-config-${spring.profiles.active}.yml", factory = YamlPropertySourceFactory.class)
@Data
public class ManagerProperties {
    private String url;
    private Map<String, Object> map;
}

@Slf4j
@Data
@Component
public class EnvBean implements SmartInitializingSingleton {

    @Resource
    private final ManagerProperties managerProperties;

    @Resource
    private final XssFilterProperties xssFilterProperties;

    @Override
    public void afterSingletonsInstantiated() {
        // 注意PropertySource在收集环境之后扫描作为bean
        log.info("PropertySource:{}", managerProperties);
        log.info("PropertySource:{}", xssFilterProperties);
    }
}

public class YamlPropertySourceFactory extends DefaultPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        String sourceName = name != null ? name : resource.getResource().getFilename();
        if (!resource.getResource().exists()) {
            return new PropertiesPropertySource(sourceName, new Properties());
        } else if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
            Properties propertiesFromYaml = loadYml(resource);
            return new PropertiesPropertySource(sourceName, propertiesFromYaml);
        } else {
            return super.createPropertySource(name, resource);
        }
    }

    private Properties loadYml(EncodedResource resource) throws IOException {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());
        factory.afterPropertiesSet();
        return factory.getObject();
    }
}

@Slf4j
@Component
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor/*需要在META-INF/spring.factories中配置*/, EnvironmentAware, ResourceLoaderAware, ApplicationContextAware, SmartInitializingSingleton {

    private Environment environment;
    private ResourceLoader resourceLoader;
    private ApplicationContext applicationContext;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void afterSingletonsInstantiated() {
        log.info("Bean实例化完成,环境:{}", environment);
        log.info("Bean实例化完成,资源加载器:{}", resourceLoader);
        log.info("Bean实例化完成,上下文:{}", applicationContext);
    }

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        log.info("执行环境收集完毕..."); // 控制台没有打印日志?
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
应用上下文初始化
/**
 * 应用上下文初始化器,需要在META-INF/spring.factories中配置
 */
@Slf4j
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        log.info("自定义容器上下文初始化器: ApplicationContextInitializer......");
    }
}
BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor
@Component
@Slf4j
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        log.info("自定义:BeanDefinitionRegistryPostProcessor->postProcessBeanDefinitionRegistry");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("自定义:BeanDefinitionRegistryPostProcessor->postProcessBeanFactory");
    }
}


@Component
@Slf4j
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("自定义:MyBeanFactoryPostProcessor->postProcessBeanFactory");
    }
}
Bean的生命周期
@Component
@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        My my = bean.getClass().getAnnotation(My.class);
        if (my != null) {
            // org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator postProcessBeforeInitialization创建代理类
            log.info("自定义:beanName=" + beanName + " BeanPostProcessor->postProcessBeforeInitialization");
        }
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        My my = bean.getClass().getAnnotation(My.class);
        if (my != null) {
            log.info("自定义:beanName=" + beanName + " BeanPostProcessor->postProcessAfterInitialization");
        }
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}



/**
 * 用于MyBeanPostProcessor中实现bean自定义实例化逻辑
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface My {
}

@Slf4j
@Component
@My
public class TestBean implements InitializingBean, SmartInitializingSingleton, ApplicationRunner, CommandLineRunner, DisposableBean {

    public TestBean() {
        log.info("1、构造函数调用...");
    }

    @PostConstruct
    public void post() {
        log.info("2、call @PostConstruct...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("3、call InitializingBean...");
    }

    // 实现SmartInitializingSingleton的接口后,当所有单例bean都初始化完成以后,
    // Spring的IOC容器会回调该接口的 afterSingletonsInstantiated()方法。
    @Override
    public void afterSingletonsInstantiated() {
        log.info("4、所有单例bean都初始化完成以后 call afterSingletonsInstantiated...");
    }


    // SpringApplication.afterRefresh() 之后执行
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("5、call ApplicationRunner...");
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("6、call CommandLineRunner...");
    }

    // bean销毁触发
    @PreDestroy
    public void PreDestroy() {
        log.info("7、call @PreDestroy...");
    }

    @Override
    public void destroy() throws Exception {
        log.info("8、call destroy...");
    }
}


@Slf4j
@Component
public class MyBeanFactoryAware implements BeanFactoryAware, ApplicationContextAware, CommandLineRunner {

    private static BeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        MyBeanFactoryAware.beanFactory = beanFactory;
    }

    @Override
    public void run(String... args) {
        // 销毁bean
        DefaultListableBeanFactory factory = (DefaultListableBeanFactory) MyBeanFactoryAware.beanFactory;
//        factory.destroySingleton("testBean");
//        factory.removeBeanDefinition("testBean");

        if (MyBeanFactoryAware.applicationContext instanceof AnnotationConfigServletWebServerApplicationContext) {
            AnnotationConfigServletWebServerApplicationContext app = (AnnotationConfigServletWebServerApplicationContext) MyBeanFactoryAware.applicationContext;

            log.info("factory == app.getBeanFactory() = {}", factory == app.getBeanFactory());

            log.info("销毁bean -> testBean");
            app.removeBeanDefinition("testBean");
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        MyBeanFactoryAware.applicationContext = applicationContext;
    }
}

SpringBoot启动流程可以分为以下几个步骤: 1. 确定应用程序类型。在启动SpringBoot时,首先需要确定应用程序的类型。这可以通过设置启动类的注解来实现,比如使用@SpringBootApplication注解。 2. 创建SpringBoot应用程序上下文。在确定应用程序类型后,SpringBoot会创建一个应用程序上下文(ApplicationContext)对象。这个上下文对象是整个应用程序的核心,包含了所有的配置信息和Bean定义。 3. 加载配置文件。SpringBoot会自动加载并解析应用程序的配置文件,包括application.properties或application.yml等。这些配置文件可以用来配置应用程序的各种属性,如数据库连接、端口号等。 4. 扫描和注册Bean。SpringBoot会扫描应用程序中的所有类,并将符合条件的类注册为Bean。这可以通过@ComponentScan注解来实现,它会扫描指定包及其子包中的所有类。 5. 执行Bean的初始化和依赖注入。在注册Bean后,SpringBoot会执行Bean的初始化操作,并将其依赖的其他Bean注入到其中。这可以通过使用@Autowired注解来实现。 6. 启动应用程序。在完成上述步骤后,SpringBoot启动应用程序。这将导致应用程序开始监听指定的端口,并处理来自客户端的请求。 总而言之,SpringBoot启动流程包括确定应用程序类型、创建应用程序上下文、加载配置文件、扫描和注册Bean、执行Bean的初始化和依赖注入,最后启动应用程序。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [9千字长文带你了解SpringBoot启动过程--史上最详细 SpringBoot启动流程-图文并茂](https://blog.csdn.net/weixin_44947701/article/details/124055713)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值