本文主要介绍ApplicationContext在Spring中各个子类的作用和区别
一、ApplicationContext子类体系图
从图中我们可以得到两个重要信息:
- ApplicationContext的子类都是继承自AbstractApplicationContext
- AbstractApplicationContext的子类分为两类,一类是GenericApplicationContext的子类,一类是AbstractRefreshableApplicationContext的子类.
接下来我们沿着这两个特点进行分析
1.1.AbstractApplicationContext
1.1.1.作用介绍
我们先来看下源码中的注释对ApplicationContext作用的定位:
/*Abstract implementation of the {@link org.springframework.context.ApplicationContext}
* interface. Doesn't mandate the type of storage used for configuration; simply
* implements common context functionality. Uses the Template Method design pattern,
* requiring concrete subclasses to implement abstract methods.
*
* <p>In contrast to a plain BeanFactory, an ApplicationContext is supposed
* to detect special beans defined in its internal bean factory:
* Therefore, this class automatically registers
* {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors},
* {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessors}
* and {@link org.springframework.context.ApplicationListener ApplicationListeners}
* which are defined as beans in the context.
*
* <p>A {@link org.springframework.context.MessageSource} may also be supplied
* as a bean in the context, with the name "messageSource"; otherwise, message
* resolution is delegated to the parent context. Furthermore, a multicaster
* for application events can be supplied as "applicationEventMulticaster" bean
* of type {@link org.springframework.context.event.ApplicationEventMulticaster}
* in the context; otherwise, a default multicaster of type
* {@link org.springframework.context.event.SimpleApplicationEventMulticaster} will be used.
*
* <p>Implements resource loading through extending
* {@link org.springframework.core.io.DefaultResourceLoader}.
* Consequently treats non-URL resource paths as class path resources
* (supporting full class path resource names that include the package path,
* e.g. "mypackage/myresource.dat"), unless the {@link #getResourceByPath}
* method is overwritten in a subclass.
*/
- AbstractApplication是对ApplicationContext接口的一个抽象实现类,它不持有任何配置,仅仅是对公共上下文功能的实现.使用模版方法设计模式,需要子类实现其抽线方法
- 与BeanFactory相比,ApplicationContext的作用是检测内部Bean工厂的特殊bean的定义,因此它会有以下操作:
- 自动把BeanFactoryPostProcessors、BeanPostProcessors、ApplicationListeners注册成bean
- 在context中以bean的形式提供MessageSource,bean名称为messageSource
- 在context中以bean的形式提供ApplicationEventMulticaster,bean名称为applicationEventMulticaster,并提供默认实现SimpleApplicationEventMulticaster
- 通过继承DefaultResourceLoader来实现资源加载功能
接下来我们来看下AbstractApplicationContext具体做了哪些工作
1.1.2.AbstractApplicationContext功能
1.1.2.1.对ApplicationContext接口的实现
1.1.2.1.1.对ApplicationContext接口本身定义的实现
ApplicationContext接口定义:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
AbstractApplicationContext通过持有对应属性值来实现:
private String id = ObjectUtils.identityToString(this);
private String displayName = ObjectUtils.identityToString(this);
private ApplicationContext parent;
private long startupDate;
- 其中ApplicationName默认为空
- getAutowireCapableBeanFactory通过抽象方法getBeanFactory有子类实现,
1.1.2.1.2.对ApplicationContext父接口EnvironmentCapable的实现
AbstractApplicationContext 定义了一个ConfigurableEnvironment属性:
private ConfigurableEnvironment environment;
ConfigurableEnvironment 里面持有当前应用yml文件中所用变量信息.
使用方法:
application.yml配置:
app.name: springmvc
1.通过ConfigurableEnvironment获取:
在ApplicationContext中定义的ConfigurableEnvironment,实际的子类是StandardEnvironment.
@SpringBootApplication
public class SpringMvcApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringMvcApp.class,args);
StandardEnvironment standardEnvironment = (StandardEnvironment) context.getEnvironment();
String appName = standardEnvironment.getProperty("app.name");
System.out.println("appName:"+appName);
}
}
appName:springmvc
2.占位符获取
@Service
public class UserServiceImpl implements UserService , InitializingBean {
@Value("${app.name}")
private String appName;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("占位符获取appName:"+appName);
}
}
1.1.2.1.2.对ApplicationContext父接口ApplicationEventPublisher的实现
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
ApplicationEventPublisher接口是发送容器事件的接口,通过观察者模式实现,会在容器不同阶段发送不同的ApplicationEvent.
AbstractApplicationContext在refresh函数中会调用initApplicationEventMulticaster初始化一个ApplicationEventMulticaster,默认子类为:SimpleApplicationEventMulticaster,用于发送ApplicationEvent和管理当前应用中注册的ApplicationListener.
你也可以定义自己的ApplicationEventMulticaster,设置bean名称为applicationEventMulticaster,就可以替换默认的实现.
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
我们来看下ApplicationEventMulticaster工作原理:
既然ApplicationEventMulticaster是通过观察者模式来实现ApplicationEvent的广播,那么ApplicationEventMulticaster的实现中一定会持有一组观察者,即一组ApplicationListener的实现.
果然在AbstractApplicationEventMulticaster,定义了一个ListenerRetriever,而这个ListenerRetriever就持有一组ApplicationListener.
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
}
private class ListenerRetriever {
...
public final Set<ApplicationListener<?>> applicationListeners;
...
}
AbstractApplicationEventMulticaster提供了添加、删除和获取ApplicationListener的功能.这里不在粘贴AbstractApplicationEventMulticaster的源码.
我们看下SimpleApplicationEventMulticaster是如何广播ApplicationEvent事件的.
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
}
从multicastEvent函数可以看出,SimpleApplicationEventMulticaster在广播ApplicationEvent事件时有两种策略:
- 设置了线程池,则将广播ApplicationEvent的任务提交到线程池异步执行
- 没有设置线程池,则同步执行广播ApplicationEvent的任务
1.1.2.1.3.对ApplicationContext父接口BeanFactory、ListableBeanFactory、HierarchicalBeanFactory的实现
AbstractApplicationContext对BeanFactory、ListableBeanFactory、HierachicalBeanFactory的实现,都通过抽象方法getBeanFactory获得子类持有的ConfigurableListableBeanFactory来实现这三个BeanFactory的功能,AbstractApplicationContext充当了一个代理的角色.
1.1.2.1.4.对ApplicationContext父接口MessageSource的实现
MessageSource是spring对国际化的实现,这里不详细介绍,后面会有文章详细介绍其原理.
1.1.2.1.5.对ApplicationContext父接口ResourcePatternResolver的实现
ResourcePatternResolver提供了根据路径查找对应资源文件的功能.
public interface ResourcePatternResolver extends ResourceLoader {
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
Resource[] getResources(String locationPattern) throws IOException;
}
AbstractApplicationContext中不具体实现其功能,而是充当代理者的角色,具体实现有PathMatchingResourcePatternResolver完成.
PathMatchingResourcePatternResolver主要解析classpath路径下的文件
1.1.2.2.对ConfigurableApplicationContext接口的实现
AbstractApplicationContext最重要的实现.
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
/**
添加一个BeanFactoryPostProcessor,在内部BeanFactory执行refresh时,并bean definition使用之前被执行
在读取上下文配置时使用.
**/
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
/**
添加一个ApplicationListener,用于监听ApplicationEvent
***/
void addApplicationListener(ApplicationListener<?> listener);
/**
添加一个特殊资源协议的解析器
***/
void addProtocolResolver(ProtocolResolver resolver);
/**
从xml、properties、数据库中加载配置,来创建bean实例.
这是一个启动方法,在调用这个方法后,要不一个bean都没有,要不所有的都已经实例化完成
**/
void refresh() throws BeansException, IllegalStateException;
/**
注册jvm shutdown 钩子函数
**/
void registerShutdownHook();
/**
关闭context,释放子类持有的所有资源
***/
@Override
void close();
/**
判断context是否启动
***/
boolean isActive();
/**
获取内部bean工厂
***/
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
ConfigurableApplicationContext的作用?
ConfigurableApplicationContext 重点在于设置应用的相关组件,而ApplicationContext接口重点在于获取配置.
下面主要看下refresh函数,该函数定义了context初始化的主要流程,其中就包括初始化容器中bean的主流程.
我们看下refresh函数做了哪些工作?
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
prepareRefresh阶段
该阶段主要设置启动时间和启动标识,可以被子类覆盖,但覆盖逻辑里面一定要调用super.prepareRefresh();
obtainFreshBeanFactory阶段
获取子类持有的BeanFactory.
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
refreshBeanFactory()是一个抽象函数,只有当前ApplicationContext是AbstractRefreshableApplicationContext的子类时才有具体逻辑,如下:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
如果当前ApplicationContext已经持有了BeanFactory实例,那么重新销毁所有的bean,并重新加载,相当于每次返回一个新的BeanFactory实例.
prepareBeanFactory阶段
配置BeanFactory设置内置的Bean和相关配置如classloader、el表达式解析器等
postProcessBeanFactory阶段
这时Beanfactory已经初始化完成,所有的bean definition已加载,但是还未实例bean,允许AbstractApplication的子类对BeanFactory进行修改,
如注册BeanPostProcessors.
invokeBeanFactoryPostProcessors阶段
实例化并执行所有BeanFactoryPostProcessor的bean,如有设置了顺序,则按顺序执行.
在springboot应用中,在这个过程开始ConfigurationClassPostProcessor来扫描用户系统的class,并将其转化成Bean definition注册到BeanFactory中.
registerBeanPostProcessors阶段
实例化所有的BeanPostProcessor ,并注册
initMessageSource阶段
初始化国际化相关配置
initApplicationEventMulticaster阶段
设置ApplicationEvent广播控制器
onRefresh阶段
模版方法,可以用于初始化特殊的bean
registerListeners阶段
注册ApplicationListener,用于监听ApplicationEventMulticaster广播的ApplicationEvent事件
finishBeanFactoryInitialization阶段-bean生命周期开始阶段
这个阶段才开始将剩余的Bean进行初始化,用户设置的非懒加载的bean都在这阶段完成.
如@Controller、@Service、@Compenont等修饰的.
finishRefresh阶段
ApplicationContext refresh流程完成,容器初始化完成,做以下工作
- 发送ContextRefreshedEvent事件
- 删除Context -level 缓存,如扫描到的类信息
- 注册LifecycleProcessor,并执行onRefresh方法
1.1.2.5.对Lifecycle接口的实现
生命周期接口,没有看到在哪里使用到.
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
1.2GenericApplicationContext和AbstractRefreshableApplicationContext对比
1.2.1.继承关系对比
先贴两张图,看下两者的继承关系:
GenericApplicationContext继承关系
AbstractRefreshableApplicationContext继承关系
从继承关系上看GenericeApplicationContext实现了BeanDefinitionRegistry接口,BeanDefinitionRegistry 有什么作用:
public interface BeanDefinitionRegistry extends AliasRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);
}
BeanDefinitionRegistry提供了注册Bean Definition的功能,当前其子类的实现也会持有这些Bean Definitions.
1.2.2.AbstractApplicationContext抽象方法实现对比
GenericApplicationContext
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
...
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}
...
}
AbstractRefreshableApplicationContext
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
}
GenericApplicationContext和AbstractRefreshableApplicationContext在实现AbstractApplicationContext的refreshBeanFactory有区别:
- GenericApplicationContext 没有做任何动作,只是判断了一下当前refresh的次数,最多只能一次.
- AbstractRefreshableApplicationContext:每次refresh都会重新生成BeanFactory,并重新加载Bean,加载bean definitions通过loadBeanDefinitions抽象方法,尤其子类实现.
总结:
- GenericApplicationContext子类只会调用一次refresh过程,并且可以由其他组件向它组册Bean Definition
- AbstractRefreshableApplicationContext支持多次refresh,但是需要子类提供bean配置地址
二、GenericApplicationContext子类分析
我们先来看下GenericeApplicationContext有哪些子类,然后逐个介绍:
2.1GenericWebApplicationContext和其子类
GenericWebApplicationContext对在web环境下GenericApplicationContext实现.
有以下功能:
- 可以基于编程配置web相关信息,而不是传统的web.xml.
- web相关的配置通过WebApplicationInitializer在tomcat启动后,调用onStartup方法配置servlet/filter/listener等信息.
- 添加ThemeSource bean,用于web环境的主题切换
ServletWebServerApplicationContext
ServletWebServerApplicationContext是GenericWebApplicationContext的直接子类,相比于GenericWebApplicationContext,
ServletWebServerApplicationContext增加了创建、初始化一个web server的功能.
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
ServletWebServerApplicationContext是可以面向开发者直接使用的一个web 类型的ApplicationContext,但是spring提供了更好的选择.
AnnotationConfigServletWebServerApplicationContext和XmlServletWebServerApplicationContext.
AnnotationConfigServletWebServerApplicationContext
该context可以根据一个配置了配置文件路径也是扫描bean的路径或包名的@Configuration类,来初始化我们的应用,完成bean的加载等.
在springboot中
@SpringBootApplication
public class SpringMvcApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringMvcApp.class,args);
}
}
SpringApplication.run返回的ApplicationContext 实际就是AnnotationConfigServletWebServerApplicationContext
XmlServletWebServerApplicationContext
相比于AnnotationConfigServletWebServerApplicationContext通过注解方式配置bean的配置文件、资源文件,XmlServletWebServerApplicationContext是通过提供相应的构造函数传入文件路径或者通过load方法加载相应的资源文件.
public class XmlServletWebServerApplicationContext
extends ServletWebServerApplicationContext {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlServletWebServerApplicationContext() {
this.reader.setEnvironment(this.getEnvironment());
}
public XmlServletWebServerApplicationContext(Resource... resources) {
load(resources);
refresh();
}
public XmlServletWebServerApplicationContext(String... resourceLocations) {
load(resourceLocations);
refresh();
}
public XmlServletWebServerApplicationContext(Class<?> relativeClass,
String... resourceNames) {
load(relativeClass, resourceNames);
refresh();
}
public void setValidating(boolean validating) {
this.reader.setValidating(validating);
}
public final void load(Resource... resources) {
this.reader.loadBeanDefinitions(resources);
}
public final void load(String... resourceLocations) {
this.reader.loadBeanDefinitions(resourceLocations);
}
public final void load(Class<?> relativeClass, String... resourceNames) {
Resource[] resources = new Resource[resourceNames.length];
for (int i = 0; i < resourceNames.length; i++) {
resources[i] = new ClassPathResource(resourceNames[i], relativeClass);
}
this.reader.loadBeanDefinitions(resources);
}
}
加载资源的方式:
- 构造函数传入
- 调用load方法
2.2.AnnotationConfigApplicationContext和GenericXmlApplicationContext
AnnotationConfigApplicationContext/GenericXmlApplicationContext同AnnotationConfigServletWebServerApplicationContext/XmlServletWebServerApplicationContext类似
- AnnotationConfigApplicationContext是通过@Configuration类来加载资源文件,初始化当前ApplicationContext的.
- GenericXmlApplicationContext通过特定文件加载资源
不同的是:AnnotationConfigApplicationContextAnnotationConfigApplicationContext/GenericXmlApplicationContext是非web的ApplicationContext,AnnotationConfigServletWebServerApplicationContext/XmlServletWebServerApplicationContext是支持web服务的context,可以提供对外的web服务.
假如你要写一个tcp服务,可以用这两者中的一个作为你管理bean的容器,只不过你需要自己在AbstractApplicationContext.refresh执行的某一个步骤或其他时机,完成自己的端口监听等.
或者,当前你的服务不需要对外提供服务,你也可以选择该这两个context.
2.3.StaticApplicationContext和其子类
StaticApplicationContext和StaticWebApplicationContext不会扫描任何文件,而是通过相应的方法直接注册bean,一般用于测试.
2.4.GenericGroovyApplicationContext
GenericGroovyApplicationContext提供了spring对Groovy的支持,可以加载Groovy bean definition,并完成bean的注册.
2.5.GenericReactiveWebApplicationContext和其子类
GenericReactiveWebApplicationContext和ReactiveWebServerApplicationContext同GenericWebApplicationContext和ServletWebServerApplicationContext功能类似,只不过是对reactive环境的支持.
- GenericReactiveWebApplicationContext不会启动一个web server,资源路径使用相对路径
- ReactiveWebServerApplicationContext启动一个webserver
二、AbstractRefreshableApplicationContext子类分析
AbstractRefreshableApplicationContext体系基本上和GenericApplicationContext类似,它们最本质的区别就是:
在refreshBeanFactory阶段AbstractRefreshableApplicationContext体系的ApplicationContext会返回一个新的BeanFactory,并重新加载bean.
而GenericApplicationContext体系的ApplicationContext会一直使用refresh前创建的BeanFactory.
AbstractRefreshableApplicationContext的好处是可以执行多次refresh.