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;
}
}