Spring的refresh()方法相关异常解析

作者:xtayfjpk 时间:2021-12-08 07:39:07 

Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。

如果是经常使用Spring,特别有自己新建ApplicationContext对象的经历的人,肯定见过这么几条异常消息:

1.LifecycleProcessornotinitialized-call'refresh'beforeinvokinglifecyclemethodsviathecontext:......

2.BeanFactorynotinitializedoralreadyclosed-call'refresh'beforeaccessingbeansviatheApplicationContext

3.ApplicationEventMulticasternotinitialized-call'refresh'beforemulticastingeventsviathecontext:......

第一条消息是说LifecycleProcessor对象没有初始化,在调用context的生命周期方法之前必须调用'refresh'方法

第二条消息是说BeanFactory对象没有初始化或已经关闭了,使用ApplicationContext获取Bean之前必须调用'refresh'方法

第三条消息是说ApplicationEventMulticaster对象没有初始化,在context广播事件之前必须调用'refresh'方法

这几条异常消息都与refresh方法有关,那抛出这些异常的原因到底是什么,为什么在这么多情况下一定要先调用refresh方法(定义在AbstractApplicationContext类中),在此这前我们先看看refresh方法中又干了些什么?


public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//刷新之前的准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置
prepareRefresh();
//由子类去刷新BeanFactory(如果还没创建则创建),并将BeanFactory返回
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备BeanFactory以供ApplicationContext使用
prepareBeanFactory(beanFactory);
try {
//子类可通过格式此方法来对BeanFactory进行修改
postProcessBeanFactory(beanFactory);
//实例化并调用所有注册的BeanFactoryPostProcessor对象
invokeBeanFactoryPostProcessors(beanFactory);
//实例化并调用所有注册的BeanPostProcessor对象
registerBeanPostProcessors(beanFactory);
//初始化MessageSource
initMessageSource();
//初始化事件广播器
initApplicationEventMulticaster();
//子类覆盖此方法在刷新过程做额外工作
onRefresh();
//注册应用 * ApplicationListener
registerListeners();
//实例化所有non-lazy-init bean
finishBeanFactoryInitialization(beanFactory);
//刷新完成工作,包括初始化LifecycleProcessor,发布刷新完成事件等
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}

与此三条异常消息相关的方法分别为:

finishRefresh();obtainFreshBeanFactory();initApplicationEventMulticaster();


protected void finishRefresh() {
// //初始化LifecycleProcessor
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

如果没有调用finishRefresh方法,则lifecycleProcessor成员为null。


protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
 refreshBeanFactory();//刷新BeanFactory,如果beanFactory为null,则创建
 ConfigurableListableBeanFactory beanFactory = getBeanFactory();
 if (logger.isDebugEnabled()) {
   logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
 }
 return beanFactory;
}

refreshBeanFactory()为一抽象方法,真正实现在AbstractRefreshableApplicationContext类中:


@Override
protected final void refreshBeanFactory() throws BeansException {
 if (hasBeanFactory()) {//如果beanFactory已经不为null,则销毁beanFactory中的Bean后自行关闭
   destroyBeans();
   closeBeanFactory();
 }
 try {
   DefaultListableBeanFactory beanFactory = createBeanFactory();//创建beanFactory
   beanFactory.setSerializationId(getId());
   customizeBeanFactory(beanFactory);
   loadBeanDefinitions(beanFactory);
   synchronized (this.beanFactoryMonitor) {
     this.beanFactory = beanFactory;//对beanFactory成员进行赋值
   }
 }
 catch (IOException ex) {
   throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
 }
}

如果没有调用obtainFreshBeanFactory()方法则beanFactory成员为null。


protected void initApplicationEventMulticaster() {
 ConfigurableListableBeanFactory beanFactory = getBeanFactory();
 if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
   this.applicationEventMulticaster =
       beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
   if (logger.isDebugEnabled()) {
     logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
   }
 }
 else {
   this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
   beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
   if (logger.isDebugEnabled()) {
     logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
         APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
         "': using default [" + this.applicationEventMulticaster + "]");
   }
 }
}

而这三个方法调用都在refresh()方法中,由上面的分析可知,如果没有调用refresh方法,则上下文中的lifecycleProcessor,beanFactory,applicationEventMulticaster成员都会为null。至此可以来详细分析这三条异常消息的缘由了。

下面是针对上面三条异常消息的三段测试代码,顺序相对应:


1. public static void main(String[] args) {
 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
 applicationContext.setConfigLocation("application-context.xml");
 applicationContext.start();
 applicationContext.close();
}
2. public static void main(String[] args) {
 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
 applicationContext.setConfigLocation("application-context.xml");
 applicationContext.getBean("xtayfjpk");
 applicationContext.close();
}
3. public static void main(String[] args) {
 GenericApplicationContext parent = new GenericApplicationContext();
 AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
 context.setParent(parent);
 context.refresh();
 context.start();
 context.close();
}

对于第一条异常消息,异常堆栈出错在applicationContext.start();下面是start()方法源码:


public void start() {
 getLifecycleProcessor().start();
 publishEvent(new ContextStartedEvent(this));
}

可以看到start()方法中要先获取lifecycleProcessor对象,而默认构造方法中并没用调用refresh方法,所以lifecycleProcessor为null,故而在getLifecycleProcessor()方法中抛出了此异常消息。这其中提到了生命周期方法,其实就是定义在org.springframework.context.Lifecycle接口中的start(),stop(),isRunning()三个方法,如果是刚开始学习Spring的话,创建ClassPathXmlApplicationContext对象时应该是这样的:ClassPathXmlApplicationContextapplicationContext=newClassPathXmlApplicationContext("application-context.xml");这样直接调用start()方法却又不会出现异常,这是为什么呢?这是因为ClassPathXmlApplicationContext(StringconfigLocation)这个构造方法最终调用的是:


public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
 super(parent);
 setConfigLocations(configLocations);
 if (refresh) {//refresh传递值为true,这样就自动调用了refresh方法进行了刷新
   refresh();
 }
}

第二条异常消息,异常堆栈出错在applicationContext.getBean("xtayfjpk"),applicationContext.getBean()方法调用的是上下文中beanFactory的getBean()方法实现的,获取BeanFactory对象的代码在其基类ConfigurableListableBeanFactory中的getBeanFactory()方法中:


@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
 synchronized (this.beanFactoryMonitor) {
   if (this.beanFactory == null) {
     throw new IllegalStateException("BeanFactory not initialized or already closed - " +
         "call 'refresh' before accessing beans via the ApplicationContext");
   }
   return this.beanFactory;
 }
}

由于ClassPathXmlApplicationContext的默认构造方法没有调用refresh()方法,所以beanFactory为null,因此抛出异常。

第三条异常消息,异常堆栈出错在context.refresh(),但是如果没有设置父上下文的话context.setParent(parent),例子代码是不会出现异常的。这是因为在refresh方法中的finishRefresh()方法调用了publishEvent方法:


public void publishEvent(ApplicationEvent event) {
 Assert.notNull(event, "Event must not be null");
 if (logger.isTraceEnabled()) {
   logger.trace("Publishing event in " + getDisplayName() + ": " + event);
 }
 getApplicationEventMulticaster().multicastEvent(event);
 if (this.parent != null) {
   this.parent.publishEvent(event);
 }
}

从上面可以看到:如果父上下文不为null,则还需要调用父容器的pushlishEvent方法,而且在该方法中调用了getApplicationEventMulticaster()方法以获取一个事件广播器,问题就出现在这里:


private ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
 if (this.applicationEventMulticaster == null) {//如果为null则抛异常
   throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
       "call 'refresh' before multicasting events via the context: " + this);
 }
 return this.applicationEventMulticaster;
}

而applicationEventMulticaster就是在refresh方法中的initApplicationEventMulticaster方法在实例化的,则于父上下文没有调用过refresh方法所以父上下文的applicationEventMulticaster成员为null,因此抛出异常。

综上所述,其实这三条异常消息的根本原因只有一个,就是当一个上下文对象创建后没有调用refresh()方法。在Spring中ApplicationContext实现类有很多,有些实现类在创建的过程中自动调用了refresh()方法,而有些又没有,如果没有则需要自己手动调用refresh()方法。一般说来实现WebApplicationContext接口的实现类以及使用默认构造方法创建上下文对象时不会自动refresh()方法,其它情况则会自动调用。

总结

Spring集成Redis详解代码示例

Spring AOP拦截-三种方式实现自动代理详解

spring配置扫描多个包问题解析

如有不足之处,欢迎留言指出。

来源:https://www.2cto.com/kf/201504/389182.html

标签:spring,refresh方法
0
投稿

猜你喜欢

  • 详解Spring中bean的几种注入方式

    2023-02-12 20:25:07
  • 浅谈@PostConstruct不被调用的原因

    2023-03-22 11:40:29
  • Spring Security过滤器链体系的实例详解

    2023-08-25 03:24:15
  • Java手动实现Redis的LRU缓存机制

    2023-07-31 12:51:30
  • Mybatis实现SQL存储流程详解

    2022-09-11 05:17:05
  • java编写Http服务器下载工具

    2021-11-08 08:07:38
  • SpringBoot中Dozer的使用小结

    2023-11-25 01:24:38
  • 代码分析Android消息机制

    2023-07-26 09:44:44
  • 快速理解Java垃圾回收和jvm中的stw

    2021-09-06 20:27:17
  • 详解commons-pool2池化技术

    2021-09-10 10:56:29
  • 详解Java中方法重写和方法重载的6个区别

    2023-11-28 13:42:18
  • Java实现答答租车系统

    2022-07-12 01:38:17
  • Java实现提取QSV文件视频内容

    2023-08-24 13:33:45
  • Spring5中的WebClient使用方法详解

    2023-08-05 14:50:24
  • Mybatis generator自动生成代码插件实例解析

    2022-06-04 22:52:33
  • Java中LinkedList和ArrayList的效率分析

    2023-02-12 06:21:55
  • 使用IDEA开发配置Java Web的初始化过程

    2022-09-25 16:33:38
  • java生成指定范围随机数的多种代码

    2023-04-28 07:51:15
  • 解决idea爆红 cant resolve symbol String的问题解析

    2023-10-11 10:47:30
  • java注解的全面分析

    2023-11-25 11:28:50
  • asp之家 软件编程 m.aspxhome.com