Java 初始化器解析

一、系统初始化器介绍

  1. 类名:ApplicationContextInitializer
  2. 介绍:Spring容器刷新之前执行的一个回调函数
  3. 作用:向SpringBoot容器中注入属性
  4. 使用:继承接口自定义实现

实现方式一:自定义初始化器向SpringBoot容器中注入了属性

1.实现ApplicationContextInitializer接口

package com.gf.springboot.initializer;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.util.HashMap;
import java.util.Map;

@Order(1)
//新建一个类继承系统初始化器的接口
public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    //继承方法并实现
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        //自定义属性
        Map<String,Object> map =new HashMap<>();
        //放入属性
        map.put("key1","value1");
        //打包成一个属性
        MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer", map);
        //放入环境当中
        environment.getPropertySources().addLast(mapPropertySource);
        //输出
        System.out.println("run firstInitializer");
        //完成第一个系统初始化器的编写,接下来需要注册到容器当中
    }
}

2.spring.factories内填写接口实现

org.springframework.context.ApplicationContextInitializer=com.gf.springboot.initializer.FirstInitializer

3.key值为org.springframework.context.ApplicationContextInitializer

在controller文件中新增接口用于验证,并添加用于验证的service

SpringAccountController
package com.gf.springboot.controller;

import com.gf.springboot.bean.SpringAccount;
import com.gf.springboot.service.SpringAccountService;
import com.gf.springboot.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Optional;

@Controller
@RequestMapping("/spring")
public class SpringAccountController {
    @Autowired
    private SpringAccountService springAccountService;

    @Autowired
    private TestService testService;
    @RequestMapping("/account/{id}")
    @ResponseBody
    public String accountNum(@PathVariable(value = "id") Integer id) {
        return Optional.ofNullable(springAccountService.getById(id)).map(SpringAccount::toString).orElse("empty String");

    }

    //验证是否将自定义属性正确的注册进去
    @RequestMapping("test")
    @ResponseBody
    public String test(){
        //需要新建一个工具类,定义一个方法,使得这个接口可以调用
        return testService.test();
    }

}
TestService
package com.gf.springboot.service;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class TestService implements ApplicationContextAware {
    private ApplicationContext applicationContext;

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

    public String test(){
        return applicationContext.getEnvironment().getProperty("key3");
    }
}

运行

实现方式二:

1.实现ApplicationContextInitializer接口

package com.gf.springboot.initializer;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.util.HashMap;
import java.util.Map;

@Order(2)
//新建一个类继承系统初始化器的接口
public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    //继承方法并实现
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        //自定义属性
        Map<String,Object> map =new HashMap<>();
        //放入属性
        map.put("key2","value2");
        //打包成一个属性
        MapPropertySource mapPropertySource = new MapPropertySource("secondInitializer", map);
        //放入环境当中
        environment.getPropertySources().addLast(mapPropertySource);
        //输出
        System.out.println("run secondInitializer");
        //完成第一个系统初始化器的编写,接下来需要注册到容器当中
    }
}

2.SpringApplication类初始后设置进去

package com.gf.springboot;

import com.gf.springboot.initializer.SecondInitializer;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.gf.springboot.mapper")
public class SpringbootApplication {

    public static void main(String[] args) {
//        SpringApplication.run(SpringbootApplication.class, args);

        //换一种启动方式
        //先new一个SpringApplication
        SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
        //添加一个系统初始化器
        springApplication.addInitializers(new SecondInitializer());
        //启动
        springApplication.run(args);
    }

}

实现方式三:

1.实现ApplicationContextInitializer接口

package com.gf.springboot.initializer;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.util.HashMap;
import java.util.Map;

@Order(3)
//新建一个类继承系统初始化器的接口
public class ThirdInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    //继承方法并实现
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        //自定义属性
        Map<String,Object> map =new HashMap<>();
        //放入属性
        map.put("key3","value3");
        //打包成一个属性
        MapPropertySource mapPropertySource = new MapPropertySource("thirdInitializer", map);
        //放入环境当中
        environment.getPropertySources().addLast(mapPropertySource);
        //输出
        System.out.println("run thirdInitializer");
        //完成第一个系统初始化器的编写,接下来需要注册到容器当中
    }
}

2.application.properties内填写接口实现

server.port=8080
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.gf.springboot.bean
mybatis.configuration.map-underscore-to-camel-case=true
context.initializer.classes=com.gf.springboot.initializer.ThirdInitializer

3.key值为context.initializer.classes

注意:

  1. 都需要实现ApplicationContextInitializer接口
  2. order值越小越先执行
  3. application.properties中定义的优先于其它方式

二、SpringFactoriesLoader介绍

 自定义系统初始化器是如何被SpringBoot容器识别并加载到容器类中

  1. 框架内部使用的通用工厂加载机制
  2. 从classpath下多个jar包特定位置读取文件并初始化类
  3. 文件类型必须是kv形式,即properties类型
  4. key是全限定名(抽象类|接口),value是实现,多个实现用逗号分隔

作用:Spring Boot框架中从类路径jar包中读取特定文件实现扩展类的载入

流程:

三、系统初始化器原理解析

ApplicationContextInitializer

  系统初始化器的实现是如何被调用的以及背后的实现原理

作用:

  1. 上下文刷新即refresh方法前调用
  2. 用来编码设置一些属性变量通常用在web环境中
  3. 可以通过order接口进行排序

四、总结

  1. 介绍下SpringFactoriesLoader?  这个类是Springboot工厂中的加载类,springboot用它来完成扩展点的实现的载入
  2. SpringFactoriesLoader如何加载工厂类?读取指定路径下的指定文件,读成一个properties对象,然后依次遍历文件内容,组装成类名和对应的实现,然后依次遍历,通过order进行排序
  3. 系统初始化器的作用?是SpringBoot容器的一个回调接口,通过它向容器定义我们的属性
  4. 系统初始化器调用的时机?run方法中的prepareContext方法中
  5. 如何自定义实现系统初始化器?
  6. 自定义实现系统初始化器有哪些注意事项?order值的大小排序问题,不同实现方式使得order值失效
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值