欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

springboot ApplicationContextInitializer的三种使用方法小结

程序员文章站 2022-06-25 07:54:18
目录applicationcontextinitializer的三种使用方法概述1、使用spring.factories方式2、application.properties添加配置方式3、直接通过ad...

applicationcontextinitializer的三种使用方法

概述

applicationcontextinitializer是在springboot启动过程(refresh方法前)调用,主要是在applicationcontextinitializer中initialize方法中拉起了configurationclasspostprocessor这个类(我在springboot启动流程中有描述),通过这个processor实现了beandefinition。

言归正传,applicationcontextinitializer实现主要有3中方式:

1、使用spring.factories方式

首先我们自定义个类实现了applicationcontextinitializer,然后在resource下面新建/meta-inf/spring.factories文件。

 
public class demo01applicationcontextinitializer implements applicationcontextinitializer<configurableapplicationcontext> {
    @override
    public void initialize(configurableapplicationcontext configurableapplicationcontext) {
        system.out.println("user add method ==> applicationcontextinitializer");
    }
}

springboot ApplicationContextInitializer的三种使用方法小结

springboot ApplicationContextInitializer的三种使用方法小结

这个加载过程是在springapplication中的getspringfactoriesinstances()方法中直接加载并实例后执行对应的initialize方法。代码如下:

private <t> collection<? extends t> getspringfactoriesinstances(class<t> type,
			class<?>[] parametertypes, object... args) {
		classloader classloader = thread.currentthread().getcontextclassloader();
		// use names and ensure unique to protect against duplicates
		set<string> names = new linkedhashset<string>(
				springfactoriesloader.loadfactorynames(type, classloader));
		list<t> instances = createspringfactoriesinstances(type, parametertypes,
				classloader, args, names);
		annotationawareordercomparator.sort(instances);
		return instances;
	}

2、application.properties添加配置方式

对于这种方式是通过delegatingapplicationcontextinitializer这个初始化类中的initialize方法获取到application.properties中context.initializer.classes对应的类并执行对应的initialize方法。

只需要将实现了applicationcontextinitializer的类添加到application.properties即可。如下:

springboot ApplicationContextInitializer的三种使用方法小结

下面我们看看delegatingapplicationcontextinitializer是如何加载的。看代码:

private static final string property_name = "context.initializer.classes";
private list<class<?>> getinitializerclasses(configurableenvironment env) {
		string classnames = env.getproperty(property_name);
		list<class<?>> classes = new arraylist<class<?>>();
		if (stringutils.haslength(classnames)) {
			for (string classname : stringutils.tokenizetostringarray(classnames, ",")) {
				classes.add(getinitializerclass(classname));
			}
		}
		return classes;
	}

是从配置文件中获取到对应的初始化类信息,然后执行初始化方法。

3、直接通过add方法

这个方法就比较简单,直接在springboot启动的时候,add一个实现了applicationcontextinitializer的类即可,代码如下:

@springbootapplication
public class initializerdemoapplication { 
	public static void main(string[] args) {
		//type01
		springapplication springapplication = new springapplication(initializerdemoapplication.class);
		springapplication.addinitializers(new demo01applicationcontextinitializer());
		springapplication.run(args);
 
		//springapplication.run(initializerdemoapplication.class,args);
	}
}

以上3中方法都可以实现自定义的initializer,只不过执行的顺序有差异。这里我比较感兴趣有2个,一个通过spring.factories实现spi模式,有兴趣的可以看下jdbc-starter等一些相关springboot starter。

第二个就是作为一个钩子去拉起来"一坨"的bean。

applicationcontextinitializer都干了些什么

初始化方法

org.springframework.boot.context.config.delegatingapplicationcontextinitializer

 @override
 public void initialize(configurableapplicationcontext context) {
  configurableenvironment environment = context.getenvironment();
  /**
  * 初始化环境变量中的context.initializer.classes指定的类
  **/
  list<class<?>> initializerclasses = getinitializerclasses(environment);
  if (!initializerclasses.isempty()) {
   applyinitializerclasses(context, initializerclasses);
  }
 }

也就是说没有定义的话,就不会初始化了。

org.springframework.boot.autoconfigure.sharedmetadatareaderfactorycontextinitializer

 @override
 public void initialize(configurableapplicationcontext applicationcontext) {
  /**
  * 注册一个元数据读取的工厂类
  **/
  applicationcontext.addbeanfactorypostprocessor(new cachingmetadatareaderfactorypostprocessor());
 }

org.springframework.boot.context.contextidapplicationcontextinitializer

 @override
 public void initialize(configurableapplicationcontext applicationcontext) {
  contextid contextid = getcontextid(applicationcontext);
  applicationcontext.setid(contextid.getid());
  /**
  * 注册一个contextid对象
  **/
  applicationcontext.getbeanfactory().registersingleton(contextid.class.getname(), contextid);
 }

org.springframework.boot.context.configurationwarningsapplicationcontextinitializer

 @override
 public void initialize(configurableapplicationcontext context) {
  /**
  * 注入componentscan检查处理对象
  **/
  context.addbeanfactorypostprocessor(new configurationwarningspostprocessor(getchecks()));
 }

org.springframework.boot.rsocket.context.rsocketportinfoapplicationcontextinitializer

 @override
 public void initialize(configurableapplicationcontext applicationcontext) {
   /**
  * 注入一个端口检查和设置的监听器,对应的事件rsocketserverinitializedevent
  **/
  applicationcontext.addapplicationlistener(new listener(applicationcontext));
 }

org.springframework.boot.web.context.serverportinfoapplicationcontextinitializer

 @override
 public void initialize(configurableapplicationcontext applicationcontext) {
  /**
   注册了一个监听org.springframework.boot.web.context.webserverinitializedevent事件的监听器,用于设置端口信息
  **/
  applicationcontext.addapplicationlistener(this);
 }

org.springframework.boot.autoconfigure.logging.conditionevaluationreportlogginglistener

 @override
 public void initialize(configurableapplicationcontext applicationcontext) {
  this.applicationcontext = applicationcontext;
  applicationcontext.addapplicationlistener(new conditionevaluationreportlistener());
  if (applicationcontext instanceof genericapplicationcontext) {
   // get the report early in case the context fails to load
   // 注册一个监听applicationevent事件的监听器用于打印自动配置后的日志信息
   this.report = conditionevaluationreport.get(this.applicationcontext.getbeanfactory());
  }
 }

所有的这些初始化类都没偶进行启动服务的实质性操作,都是通过注册对象,埋点,后面invokebeanfactorypostprocessors才真正调用初始化方法,而且在项目启动之前

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。