深入理解Spring IOC之扩展篇(八)、环境变量的校验

999 阅读2分钟

其他扩展可参考之前的文章:

1、深入理解Spring IOC之扩展篇(一)、自定义xml标签

2、深入理解Spring IOC之扩展篇(二)、BeanFactoryPostProcessor和BeanPostProcessor

3、深入理解Spring IOC之扩展篇(三)、InitializingBean、@PostConstruct、SmartInitializingSingleton

4、深入理解Spring IOC之扩展篇(四)、Aware接口

5、深入理解Spring IOC之扩展篇(五)、基于注解整合Spring框架

6、深入理解Spring IOC之扩展篇(六)、基于Aop的自定义注解

7、深入理解Spring IOC之扩展篇(七)、Spring中的event以及自定义event

我们在讲refresh方法的那篇中说到了一个prepareRefresh的方法,这个方法主要是记录容器的状态以及对环境变量的校验,我们来看看这个方法的代码:

protected void prepareRefresh() {
	// 1. 记录下容器开始刷新的时间
	this.startupDate = System.currentTimeMillis();
	// 2. 把容器标为激活状态
	synchronized (this.activeMonitor) {
		this.active = true;
	}

	if (logger.isInfoEnabled()) {
		logger.info("Refreshing " + this);
	}

	// 3. ClassPathXmlApplicationContext的时候调的是个空方法,跳过~
	initPropertySources();

	// 4. 调用StandardEnvironment中的validateRequiredProperties方法
	getEnvironment().validateRequiredProperties();
}

我的注释上面写的很明确,3是个空方法,另外,我曾在正篇的第三篇中说过,4这里最后是没有做任何事情的。所以我们可以得出一个结论,在默认情况下,spring容器的启动是不依赖任何的环境变量的。如果我们想增加我们自己的校验环境变量的逻辑应该怎么做呢?这里分为两种情况,对应的做法也不相同,我们分别来看一下:

有人肯定会问自定义校验环境变量的逻辑有什么用,emmm,其实我自己觉得,这个作用还是很大的,比如,你可以让你的应用跑在对应的机器上嘛。环境变量这里的信息还是非常多的,不知道各位读者注意过没有。

第一种情况,你的项目是个普通的Spring而不是SpringBoot项目,此时我们可以这么做:

配置类,仅用作配置

@Configuration
@ComponentScan("com.example.test")
public class Config {
}

负责校验的bean

@Component
public class ConfigCheckBean implements EnvironmentAware {

    private ConfigurableEnvironment environment;

    @Override
    public void setEnvironment(Environment environment) {
        if (environment instanceof ConfigurableEnvironment){
            ConfigurableEnvironment environment1 = (ConfigurableEnvironment)environment;
            this.environment = environment1;
        }
        init();
        this.environment.validateRequiredProperties();
    }

    private void init() {
        this.environment.setRequiredProperties("aaa");
    }
}

测试代码:

public static void main(String[] args) {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
}

由于我没有增加任何key为aaa的环境变量,所以此时启动当时是报错了: 第二种情况是,当你的项目是个SpringBoot项目时,我们可以这样做:

@SpringBootApplication
@MapperScan(basePackages = {"com.example.studyspringbootdemo.mybatis.mapper"})
public class StudyspringbootdemoApplication {

	public static void main(String[] args) {
	    // 将SpringApplication中的ApplicationContext替换,然后启动
		SpringApplication springBootApplication = new SpringApplication(StudyspringbootdemoApplication.class);
		springBootApplication.setApplicationContextClass(MyApplicationContext.class);
		springBootApplication.run();
	}
    
    // 继承SpringBoot中默认使用的AnnotationConfigServletWebServerApplicationContext并重写initPropertySources方法
	public static class MyApplicationContext extends AnnotationConfigServletWebServerApplicationContext{
		@Override
		protected void initPropertySources() {
		    // 因为父类的initPropertySources并不为空,所以为了保持正常运行逻辑必须调用父类方法
			super.initPropertySources();
			// 添加"aaa"的校验
			getEnvironment().setRequiredProperties("aaa");
		}
	}
}

同样的,启动会失败,因为我并没有对应环境变量: