看源码
package org.springframework.context;
/**
* Callback interface for initializing a Spring {@link ConfigurableApplicationContext}
* prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}.
*
* <p>Typically used within web applications that require some programmatic initialization
* of the application context. For example, registering property sources or activating
* profiles against the {@linkplain ConfigurableApplicationContext#getEnvironment()
* context's environment}. See {@code ContextLoader} and {@code FrameworkServlet} support
* for declaring a "contextInitializerClasses" context-param and init-param, respectively.
*
* <p>{@code ApplicationContextInitializer} processors are encouraged to detect
* whether Spring's {@link org.springframework.core.Ordered Ordered} interface has been
* implemented or if the @{@link org.springframework.core.annotation.Order Order}
* annotation is present and to sort instances accordingly if so prior to invocation.
*
* @author Chris Beams
* @since 3.1
* @see org.springframework.web.context.ContextLoader#customizeContext
* @see org.springframework.web.context.ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM
* @see org.springframework.web.servlet.FrameworkServlet#setContextInitializerClasses
* @see org.springframework.web.servlet.FrameworkServlet#applyInitializers
*/
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
上面的英文注释大概意思:在ConfigurableApplicationContext的refresh()方法之前被调用。通常在web应用中做初始化操作,比如根据ConfigurableApplicationContext#getEnvironment()注册属性源或配置文件。支持@Order()
写个小例子(springboot 项目):
MyApplicationContextInitializer 实现ApplicationContextInitializer
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>{
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("bean count:" + applicationContext.getBeanDefinitionCount());
System.out.println("BeanName列表:");
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
System.out.println(beanName);
}
}
}
需要注册一下
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import com.xiaofeng.shiro.config.MyApplicationContextInitializer;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
//关键一步:将一个或多个initializer加入至spring容器中
springApplication.addInitializers(new MyApplicationContextInitializer());
ConfigurableApplicationContext context = springApplication.run(args);
context.close();
}
}
运行结果:
这个MyApplicationContextInitializer 是什么时候调用的?看下图,在springboot 启动的时候,会调用下面的方法
现在再把这个实现类的逻辑改一下,改成获取某个bean,看是什么结果
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>{
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("初始化MyApplicationContextInitializer...");
System.out.println(applicationContext.containsBean("conversionService"));
Object con = applicationContext.getBean("conversionService");
System.out.println(con.getClass());
}
}
结果报错:
java.lang.IllegalStateException: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@71244ee8 has not been refreshed yet
这个错误是下面这段代码抛出的
protected void assertBeanFactoryActive() {
if (!this.active.get()) {
if (this.closed.get()) {
throw new IllegalStateException(getDisplayName() + " has been closed already");
}
else {
throw new IllegalStateException(getDisplayName() + " has not been refreshed yet");
}
}
}
这里先判断active 这个变量的值,如果是未激活,并且容器未关闭,则抛出这个异常。
/** Flag that indicates whether this context is currently active */
private final AtomicBoolean active = new AtomicBoolean();
也就是在从beanFactory获取bean的时候,会先判断是否为激活状态
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
那这个方法在什么时候被赋值为true?
也就是说,这个MyApplicationContextInitializer在prepareRefresh()之前执行了,故报错