ApplicationContextInitializer的使用

回眸只為那壹抹淺笑 提交于 2020-03-18 20:04:40

3 月,跳不动了?>>>

1.介绍

ApplicationContextInitializer主要用在容器刷新之前调用改接口实现类的initialize方法,并将ConfigurableApplicationContext类的实例作为参数传入。通常用于根据应用上下文进行处理的编程中。且实现类可以通过Ordered接口或 @Order注解 进行多个Initializer的排序。

2.有三种使用方式

首先定义一个测试initializer

public class TestApplicationContextInitializer
    implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("Initializer调用:" + applicationContext.getApplicationName());
    }

    @Override
    public int getOrder() {
        return 0;
    }

}

第一种:在启动类的main方法中使用

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        // SpringApplication.run(DemoApplication.class, args);
        SpringApplication application = new SpringApplication(DemoApplication.class);
        application.addInitializers(new TestApplicationContextInitializer()); // 直接在SpringApplication中添加
        application.run(args);
        System.out.println("启动完成");
    }

}

输出结果:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.5.RELEASE)

Initializer调用:
2020-03-18 19:15:09.448  INFO 87824 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication on ZZ-WZ112019 with PID 87824 (E:\java_work\demo\target\classes started by jiafeng in E:\java_work\demo)
2020-03-18 19:15:09.454  INFO 87824 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2020-03-18 19:15:09.950  INFO 87824 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 116.167 seconds (JVM running for 116.788)
启动完成

第二种:通过SPI扩展META-INF/spring.factories使用

spring.factories文件

org.springframework.context.ApplicationContextInitializer=\
com.example.demo.initializer.TestApplicationContextInitializer

启动类:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        // SpringApplication application = new SpringApplication(DemoApplication.class);
        // application.addInitializers(new TestApplicationContextInitializer()); // 直接在SpringApplication中添加
        // application.run(args);
        System.out.println("启动完成");
    }

}

输出结果:同上产生效果

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.5.RELEASE)

Initializer调用:
2020-03-18 19:20:23.812  INFO 87920 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication on ZZ-WZ112019 with PID 87920 (E:\java_work\demo\target\classes started by jiafeng in E:\java_work\demo)
2020-03-18 19:20:23.814  INFO 87920 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2020-03-18 19:20:24.057  INFO 87920 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.443 seconds (JVM running for 0.932)
启动完成

第三种:通过配置文件使用

在配置文件application.properties中添加如下配置:

context.initializer.classes=com.example.demo.initializer.TestApplicationContextInitializer

运行启动类,依然被调用。

3. Ordered排序

通过继承Ordered接口实现int getOrder()方法进行排序,设置高优先级排序则在众多initializer中会被优先调用。

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

4. 源码分析initializer运行时机

SpringApplication实例化对象时会对所有initializer进行加载。

SpringApplication的run( )方法:

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			//刷新之前准备工作,在该方法进行initialize调用
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			//进行刷新
            refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

prepareContext( )方法中

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
        //执行initialize调用
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}

在applyInitializers( )方法中对前面加载的initializer进行循环遍历调用initialize方法

    @SuppressWarnings({ "rawtypes", "unchecked" })
	protected void applyInitializers(ConfigurableApplicationContext context) {
        //遍历SpringApplication实例化时加载的所有initializer
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
					ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			initializer.initialize(context);//调用initialize实现方法
		}
	}

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!