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

  • 相关阅读:
    我开发中的用到的几个框架
    关于ASP.NETCore的分享之学习路线
    首个.NET5+Vue.js业务模块化快速开发框架【NetModular】发布
    [C#] (原创)一步一步教你自定义控件 —— 系列文章
    EFS加密
    博客园样式美化:给博客添加一个音乐播放器
    XSS语义分析
    TCP回放攻击 & DDoS脉冲攻击Hit and Run IoT僵尸网络 在DDoS攻击黑产领域最活跃
    小样本学习,阿里做得比较早,但是效果未知——小样本有3类解决方法(算法维度):迁移学习、元学习(模型基础上学习模型)、度量学习(相似度衡量,也就是搜索思路),数据维度还有GAN
    真实世界中的开集识别问题(Open-Set Recognition Problem)——Walter J. Scheirer研究是最深的,安全里已经有研究了,但是感觉只是触及了皮毛而已
  • 原文地址:https://www.cnblogs.com/gaoxufei/p/6225394.html
Copyright © 2020-2023  润新知