1、ApplicationContextInitializer初始化器解析

喜你入骨 提交于 2020-02-26 04:58:10

1.1、初始化器三种添加到容器中方式

1) 方式1:在resources目录下新建META-INF目录,新建spring.factories文件并赋值
org.springframework.context.ApplicationContextInitializer=com.lwh.springboot.initializer.FirstInitializer
@Order(1)
public class FirstInitializer implements ApplicationContextInitializer<configurableapplicationcontext> {

    @Override
    public void initialize(ConfigurableApplicationContext ctx) {
        ConfigurableEnvironment environment = ctx.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) 方式3:在application.properties中赋值,ThirdInitializer代码同FirstInitializer
   赋值context.initializer.classes=com.lwh.springboot.initializer.ThirdInitializer
测试代码:访问输出value1, value3,说明赋值成功
@RestController
public class TestController {

    @Autowired
    private TestService testService;

    @GetMapping("/test/initialize")
    public String testInitialize(){
        String value1 = testService.test("key1");
        String value3 = testService.test("key3");
        return value1 + ", " + value3;
    }
}

@Component
public class TestService implements ApplicationContextAware {

    private ApplicationContext applicationContext;

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

    public String test(String key){
        return applicationContext.getEnvironment().getProperty(key);
    }
}
3) 方式2:SecondInitializer代码同FirstInitializer,启动方式修改一下,测试方式类似
@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        //SpringApplication.run(SpringbootApplication.class, args);
        SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
        springApplication.addInitializers(new SecondInitializer());
        springApplication.run(args);
    }
}
控制台输出:
run thirdInitializer    -- ThirdInitializer标注了@Order(3)
run firstInitializer    -- FirstInitializer标注了@Order(1)
run secondInitializer   -- SecondInitializer标注了@Order(2)

规律:Order值越小,越先输出,在application.properties中定义的先输出

1.2、SpringFactoriesLoader介绍

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

1.3、初始化器解析

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

1.4、 添加原理分析

1) 定义在spring.factories文件中被SpringFactoriesLoader发现注册
2) SpringApplication初始化完毕后手动添加
3) 定义成环境变量被DelegatingApplicationContextInitializer发现注册

1.4.1、方式1分析

方式1)代码分析:定义在spring.factories文件中被SpringFactoriesLoader发现注册
@SpringBootApplication
public class SpringbootApplication {

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

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class<?>[] { primarySource }, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

public SpringApplication(Class<?>... primarySources) {
	this(null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	// 到这一步从spring.factories中加载ApplicationContextInitializer.class的实现类
	setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
	return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// Use names and ensure unique to protect against duplicates
	// 1) 从spring.factories中加载ApplicationContextInitializer.class的实现类
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	// 2) 实例化步骤1中得到的实现类
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	// 3) 根据order注解进行排序
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}
// 1) 从spring.factories中加载ApplicationContextInitializer.class的实现类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    // org.springframework.context.ApplicationContextInitializer
    String factoryClassName = factoryClass.getName();
    // 获得一个Map,map形如<key,List<String>>形式,后面getOrDefault是获取
    // org.springframework.context.ApplicationContextInitializer对应的实现类集合
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

// 带缓存功能,从各个jar包的META-INF/spring.factories文件中加载实现类,一个key可能包含多个实现
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    MultiValueMap<String, String> result = cache.get(classLoader);
    if (result != null) {
        // 缓存中有直接返回
        return result;
    }

    try {
        // FACTORIES_RESOURCE_LOCATION值是META-INF/spring.factories
        Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                                                       ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        result = new LinkedMultiValueMap<>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                // 获取key
                String factoryClassName = ((String) entry.getKey()).trim();
                // 将value逗号分隔,获得各个具体的实现类
                for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                    // 放入result中
                    result.add(factoryClassName, factoryName.trim());
                }
            }
        }
        cache.put(classLoader, result);
        // 返回的result见下图
        return result;
    }
}

// 2) 实例化步骤1中得到的实现类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, 
				                                  Object[] args, Set<String> names) {
    List<T> instances = new ArrayList<>(names.size());
    for (String name : names) {
        try {
            Class<?> instanceClass = ClassUtils.forName(name, classLoader);
            // 判断instanceClass是否是ApplicationContextInitializer的实现类
            Assert.isAssignable(type, instanceClass);
            Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
            T instance = (T) BeanUtils.instantiateClass(constructor, args);
            instances.add(instance);
        }
    }
    return instances;
}
// 3) 根据order注解进行排序
AnnotationAwareOrderComparator.sort(instances);

public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();

public static void sort(List<?> list) {
    if (list.size() > 1) {
        list.sort(INSTANCE);
    }
}

1.4.2、方式2分析

方式2)代码分析:手动添加
@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
        springApplication.addInitializers(new SecondInitializer());
        springApplication.run(args);
    }
}

public void addInitializers(ApplicationContextInitializer<?>... initializers) {
    // 方式1最终也是放入到了SpringApplication的initializers集合中
    this.initializers.addAll(Arrays.asList(initializers));
}

1.4.3、方式3分析

方式3)代码分析:在application.properties中配置,通过DelegatingApplicationContextInitializer注入
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // 这边加载之后默认有7个实现类,有一个是DelegatingApplicationContextInitializer
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    // 排完序后见下图,发现DelegatingApplicationContextInitializer在最前
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    // 方式1中分析的是SpringApplicatin的构造函数,构造函数完了之后已经加载了spring.factories的  
    // class到SpringApplication的initializers集合中,接着运行run函数
    return new SpringApplication(primarySources).run(args);
}
// 核心代码,删除了部分代码,只分析与此有关的步骤
public ConfigurableApplicationContext run(String... args) {
    try {
        context = createApplicationContext();
        // 走这一步
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        refreshContext(context);
        afterRefresh(context, applicationArguments);
    }
    return context;
}

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
                            SpringApplicationRunListeners listeners, 
                            ApplicationArguments applicationArguments, 
                            Banner printedBanner) {
    context.setEnvironment(environment);
    postProcessApplicationContext(context);
    // 走这一步,调用各个initializers的initialize方法
    applyInitializers(context);
    // 删除部分代码
}

protected void applyInitializers(ConfigurableApplicationContext context) {
    // 遍历每个initializers,调用其initialize方法
    for (ApplicationContextInitializer initializer : getInitializers()) {
        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), 
		                                                        ApplicationContextInitializer.class);
        Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
        // 调用initialize方法,第一个调用的就是DelegatingApplicationContextInitializer
        initializer.initialize(context);
    }
}
// DelegatingApplicationContextInitializer的initialize方法
public void initialize(ConfigurableApplicationContext context) {
    ConfigurableEnvironment environment = context.getEnvironment();
    List<Class<?>> initializerClasses = getInitializerClasses(environment);
    if (!initializerClasses.isEmpty()) {
        applyInitializerClasses(context, initializerClasses);
    }
}

private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
    // PROPERTY_NAME = "context.initializer.classes";
    // classNames这里是com.lwh.springboot.initializer.ThirdInitializer
    String classNames = env.getProperty(PROPERTY_NAME);
    List<Class<?>> classes = new ArrayList<>();
    if (StringUtils.hasLength(classNames)) {
        for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
            classes.add(getInitializerClass(className));
        }
    }
    return classes;
}

private void applyInitializerClasses(ConfigurableApplicationContext context,
                                                     List<Class<?>> initializerClasses) {
    Class<?> contextClass = context.getClass();
    List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();
    // 实例化Initializer对象
    for (Class<?> initializerClass : initializerClasses) {
        initializers.add(instantiateInitializer(contextClass, initializerClass));
    }
    // 调用initialize方法
    applyInitializers(context, initializers);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!