(转载)Spring的refresh()方法相关异常

如果是经常使用Spring,特别有自己新建ApplicationContext对象的经历的人,肯定见过这么几条异常消息:
1.LifecycleProcessor not initialized - call ‘refresh‘ before invoking lifecycle methods via the context: ......
2.BeanFactory not initialized or already closed - call ‘refresh‘ before accessing beans via the ApplicationContext
3.ApplicationEventMulticaster not initialized - call ‘refresh‘ before multicasting events via the context: ......

第一条消息是说LifecycleProcessor对象没有初始化,在调用context的生命周期方法之前必须调用‘refresh‘方法
第二条消息是说BeanFactory对象没有初始化或已经关闭了,使用ApplicationContext获取Bean之前必须调用‘refresh‘方法
第三条消息是说ApplicationEventMulticaster对象没有初始化,在context广播事件之前必须调用‘refresh‘方法

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

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

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();

?


1

2

3

4

5

6

7

8

9

10

11

12

13

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。

?


1

2

3

4

5

6

7

8

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

    refreshBeanFactory();//刷新BeanFactory,如果beanFactory为null,则创建

    ConfigurableListableBeanFactory beanFactory = getBeanFactory();

    if (logger.isDebugEnabled()) {

        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);

    }

    return beanFactory;

}

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

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

@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。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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()方法源码

?


1

2

3

4

public void start() {

    getLifecycleProcessor().start();

    publishEvent(new ContextStartedEvent(this));

}

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

?


1

2

3

4

5

6

7

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()方法中:

?


1

2

3

4

5

6

7

8

9

10

@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方法:

?


1

2

3

4

5

6

7

8

9

10

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()方法以获取一个事件广播器,问题就出现在这里:

?


1

2

3

4

5

6

7

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()方法,其它情况则会自动调用。

时间: 2024-10-14 00:01:14

(转载)Spring的refresh()方法相关异常的相关文章

Spring的refresh()方法相关异常

如果是经常使用Spring,特别有自己新建ApplicationContext对象的经历的人,肯定见过这么几条异常消息: 1.LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: ...... 2.BeanFactory not initialized or already closed - call 'refresh' before acces

springboot启动过程(3)-refresh方法

1  springboot在启动的时候,会调用run方法,创建环境设置spring容器,其中包含refresh方法,完成配置类解析,各种beanFactoryPostProcess和beanPostProcessor注册,web内置容器构造,国际化配置初始化等,refresh调用了父类AbstractApplicationContext的refresh方法如下. public void refresh() throws BeansException, IllegalStateException

【JavaEE】Springmvc+Spring+Hibernate搭建方法及example

前面两篇文章,分别介绍了Springmvc和Spring的搭建方法,本文再搭建hibernate,并建立SSH最基本的代码结构. Hibernate和前面两个比就比较复杂了,Hibernate是一个orm的框架,也就是负责面向对象中的对象(Object)和关系型数据库这个关系(Relation)之间的映射(Mapping).因为关系型数据库的思维方式,和编程的时候对于对象的理解是有偏差的,所以也有一些面向对象的数据库,但是随着这些orm框架的完善,面向对象的数据库就销声匿迹了. 当然,我这篇文章

spring的finishBeanFactoryInitialization方法分析

spring源码版本5.0.5 概述 该方法会实例化所有剩余的非懒加载单例 bean.除了一些内部的 bean.实现了 BeanFactoryPostProcessor 接口的 bean.实现了 BeanPostProcessor 接口的 bean,其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中. 分析 跟踪到AbstractApplicationContext.refresh()方法,找到代码finishBeanFact

spring mvc 控制器方法传数组对象的一些经验

因为项目需要在一个表单里面提交多个对象,比较好的做法就是直接在控制器方法参数里传一个数组. 由于Spring mvc框架在反射生成控制方法的参数对象的时候会调用这个类的getDeclaredConstructor方法来获得构造函数, 但是一直报NoSuchMethodException的异常. 根据这个方法的jdk文档,这个类是一个数组对象时,这个方法会抛出java.lang.NoSuchMethodException,因为接口.数组类.void.基本类型没有构造函数. 同事后来给我支了两招,使

[Guava学习笔记]Basic Utilities: Null, 前置条件, Object方法, 排序, 异常

我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3842433.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验. Null Guava用Optional表示可能为null的T类型引用. 创建:Optional.of(T)不接受null Optional.fromNullable(T)接受null Optional.absent() 查询:isPresent() get() or(T)如果为null则为T o

[转载] Spring MVC - 处理器拦截器

5.1.处理器拦截器简介 Spring Web MVC的处理器拦截器(如无特殊说明,下文所说的拦截器即处理器拦截器)类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.   5.1.1.常见应用场景 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等. 2.权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面: 3.性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间

SPring+Structs2实现的项目中进行Spring AOP时的相关小记

 SPring+Structs2实现的项目中进行Spring AOP时的相关小记 1.一般为了方便开发Structs2的项目中的action都会建立一个BaseAction如果继承了BaseAction中的子类进行AOP时,只能指定AOP中的PointCut为BaseAction 如果对应的BaseAction如果继承于ActionSupport的话,就只能定义AOP中的PointCut为ActionSupport了 因为Spring生成的代理类中,对同名的方法,只有一个,即子类重写父类的方

(转载)Spring 注解@Component,@Service,@Controller,@Repository

Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository.@Service 和 @Controller.在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层.业务层和控制层(Web 层)相对应.虽然目前这 3 个注释和 @Component 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能.所以,如果 Web 应