SpringCloud源码解析(2)--ApplicationContextInitializer配置与原理

来源:https://www.jianshu.com/p/0229dd853d77

前言

上文粗略的看了springboot启动相关的源码,这次我们来看SpringApplication构造方法中初始化的ApplicationContextInitializer的作用
ApplicationContextInitializer主要用于在spring创建上下文之前调用prepareContext的时候触发一系列操作主要是对上下文进行配置
实现了ApplicationContextInitializer接口的类都会在spring启动调用prepareContext的时候执行

ApplicationContextInitializer三种配置方式

1-项目配置文件配置

1-bootstrap.yml配置或者application.yml进行配置

如图

 

 

代码如下

/**
 * 项目配置文件注入方式
 */
public class TestInit2 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("TestInit2-----------项目配置文件注入方式");
    }
}

/**
 * application.yml项目配置文件注入方式
 */
public class TestInit2_1 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("TestInit2-1-----------项目配置文件注入方式");
    }
}

2-项目代码配置

也可以在项目中进行配置添加如下

@SpringBootApplication
public class TestServerApplication {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(TestServerApplication.class);
        springApplication.addInitializers(new TestInit0());  //添加ApplicationContextInitializer
        ConfigurableApplicationContext context = springApplication.run(args);
        context.close();
    }
}

3-spring工厂配置文件配置

也可以在项目中通过spring.factories进行配置 主要是在项目的resources下添加如下文件

 

 

在spring.factories中进行如下配置

org.springframework.context.ApplicationContextInitializer=com.tuhuanjk.cloud.config.access.TestInit1

执行结果输出如下

···

 

image.png

···

执行结果解析

执行顺序

可以在代码上使用@Order注解进行配置执行顺序 @Order的value值越小越早执行

ApplicationContextInitializer三种配置执行的默认先后顺序及源码位置

由执行结构可知在spring.factories中配置的类会加载并执行两次
同时执行默认顺序为
1 bootstrap中配置
2 spring.factories中配置
3 aoolication中配置
4 spring.factories中配置
5 代码中配置

这是因为spring boot会在创建application上下文时通知BootstrapApplicationListener并在BootstrapApplicationListener中通过SpringApplicationBuilder创建一次bootstrap的ConfigurableApplicationContext上下文并调用run方法 这里就会输出 1 和 2
然后再接着创建application上下文 这里就会输出3,4,5
具体原理可以参考我的另一篇文章
https://www.jianshu.com/p/f038d9e12554

1-在spring.factories中配置的类最先加载

通过SpringApplication构造方法中的如下代码进行读取配置文件并加载入SpringApplication的initializers集合(ArrayList)

 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

2-在boostrap中配置的加载顺序为第二

在创建bootstrap上下文时先通过ConfigFileApplicationListener将配置读入内存然后再通过DelegatingApplicationContextInitializer进行加载配置的类并调用initialize方法进行执行关键代码在DelegatingApplicationContextInitializer的initialize方法中如下代码

DelegatingApplicationContextInitializer的方法
 public void initialize(ConfigurableApplicationContext context) {
        ConfigurableEnvironment environment = context.getEnvironment();
        List<Class<?>> initializerClasses = this.getInitializerClasses(environment);
        if (!initializerClasses.isEmpty()) {
            this.applyInitializerClasses(context, initializerClasses);
        }

    }

获取在bootstrap中配置的ApplicationContextInitializer类
    private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
        String classNames = env.getProperty("context.initializer.classes");
        List<Class<?>> classes = new ArrayList();
        if (StringUtils.hasLength(classNames)) {
            String[] var4 = StringUtils.tokenizeToStringArray(classNames, ",");
            int var5 = var4.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String className = var4[var6];
                classes.add(this.getInitializerClass(className));
            }
        }

        return classes;
    }
执行在bootstrap中配置的ApplicationContextInitializer类
 private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) {
        Class<?> contextClass = context.getClass();
        List<ApplicationContextInitializer<?>> initializers = new ArrayList();
        Iterator var5 = initializerClasses.iterator();

        while(var5.hasNext()) {
            Class<?> initializerClass = (Class)var5.next();
           //将配置的类实例化并放入spring容器
            initializers.add(this.instantiateInitializer(contextClass, initializerClass));
        }
       //回调对应的initialize方法
        this.applyInitializers(context, initializers);
    }

3-application.yml中配置的加载顺序为第三

加载代码和在bootstrap.yml中配置 加载方式一样,只是因为bootstrap.yml中配置的 在创建的bootstrap上下时候就执行了而在application.yml中配置的在创建application上下文时候才执行 所以有先后顺序

4-代码中配置的加载顺序为第四

通过代码中显示的配置直接将类加载入SpringApplication的initializers集合 如下代码

springApplication.addInitializers(new TestInit0());



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Alibaba Nacos 是一个服务注册中心和配置中心,可以实现服务的注册与发现、配置的动态管理等功能,同时还提供了容灾和高可用的支持。下面简单介绍如何使用 Nacos 实现 Spring Cloud 的配置容灾。 首先,在应用的 `pom.xml` 文件中添加如下依赖: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.2.3.RELEASE</version> </dependency> ``` 然后在 `application.properties` 中配置 Nacos 的地址和应用的名称: ```properties spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 spring.cloud.nacos.discovery.namespace=your-namespace spring.cloud.nacos.config.server-addr=127.0.0.1:8848 spring.cloud.nacos.config.namespace=your-namespace spring.cloud.nacos.config.file-extension=properties spring.application.name=your-application-name ``` 其中 `server-addr` 是 Nacos 的地址,`namespace` 是命名空间,`file-extension` 是配置文件的扩展名,`application.name` 是应用的名称。 接着在 `bootstrap.properties` 中配置应用的环境和配置: ```properties spring.profiles.active=dev spring.cloud.nacos.config.prefix=${spring.application.name}-${spring.profiles.active} spring.cloud.nacos.config.group=DEFAULT_GROUP spring.cloud.nacos.config.shared-dataids=${spring.application.name}-${spring.profiles.active}.properties ``` 其中 `spring.profiles.active` 是应用的环境,`prefix` 是配置文件的前缀,`group` 是配置文件所在的分组,`shared-dataids` 是配置文件的名称。 最后,在代码中使用 `@Value` 注解来获取配置项的值: ```java @RestController public class ConfigController { @Value("${config.key}") private String configValue; @GetMapping("/config") public String getConfig() { return configValue; } } ``` 其中 `config.key` 是配置项的名称。 以上就是使用 Nacos 实现 Spring Cloud 的配置容灾的简单示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值