Lifecycle界面如何在Spring中运行?什么是"顶级单身豆"?

Suz*_*ioc 16 java spring multithreading

在Spring javadoc中说,"请注意,Lifecycle接口仅支持顶级单例bean." 这里的URL

我的LifecycleBeanTest.xml描述bean如下:

<beans ...>
    <bean id="lifecycle" class="tests.LifecycleBean"/>
</beans>
Run Code Online (Sandbox Code Playgroud)

所以它看起来很"热"和"单调".

这是什么意思?如何让Spring知道我的bean实现Lifecycle并用它做点什么?

假设我的main方法在Spring中看起来如下

public static void main(String[] args) {
    new ClassPathXmlApplicationContext("/tests/LifecycleBeanTest.xml").close();
}
Run Code Online (Sandbox Code Playgroud)

所以,它实例化上下文然后立即关闭它.

我可以在我的配置中创建一些bean,这会延迟close()执行直到应用程序执行所有操作吗?那么主方法线程等待应用程序终止?

例如,以下bean不按我想象的方式工作.也start()没有stop()被称为.

package tests;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.Lifecycle;

public class LifecycleBean implements Lifecycle {

    private static final Logger log = LoggerFactory.getLogger(LifecycleBean.class);

    private final Thread thread = new Thread("Lifecycle") {
        {
            setDaemon(false);
            setUncaughtExceptionHandler(new UncaughtExceptionHandler() {

                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    log.error("Abnormal thread termination", e);
                }
            });
        }

        public void run() {
            for(int i=0; i<10 && !isInterrupted(); ++i) {
                log.info("Hearbeat {}", i);
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    return;
                }
            }
        };
    };


    @Override
    public void start() {
        log.info("Starting bean");
        thread.start();
    }

    @Override
    public void stop() {
        log.info("Stopping bean");
        thread.interrupt();
        try {
            thread.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return;
        }
    }

    @Override
    public boolean isRunning() {
        return thread.isAlive();
    }

}
Run Code Online (Sandbox Code Playgroud)

更新1

我知道我可以在代码中等待bean.挂钩Spring本身很有意思.

Tom*_*icz 3

我从未使用过Lifecycle界面,我不确定它是如何工作的。但看起来只需调用start()上下文即可调用这些回调:

AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("...");
ctx.start();
Run Code Online (Sandbox Code Playgroud)

但通常我使用@PostConstruct/@PreDestroy注释或实现InitializingBeanDisposableBean

public class LifecycleBean implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() {
        //...
    }

    @Override
    public void destroy() {
        //...
    }

}
Run Code Online (Sandbox Code Playgroud)

请注意,我没有调用close()应用程序上下文。LifecycleBean由于您在JVM中创建非守护线程,即使main退出,该线程仍保持运行。

当您停止该线程时,JVM 存在,但没有正确关闭应用程序上下文。基本上最后一个非守护线程停止,导致整个 JVM 终止。这是一个有点 hacky 的解决方法 - 当您的后台非守护线程即将完成时,显式关闭应用程序上下文:

public class LifecycleBean implements ApplicationContextAware /* ... */ {

    private AbstractApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = (AbstractApplicationContext)applicationContext;
    }

    public void run() {
        for(int i=0; i<10 && !isInterrupted(); ++i) {
            log.info("Hearbeat {}", i);
            try {
                sleep(1000);
            } catch (InterruptedException e) {
            }
        }
        applicationContext.close();
    }

}
Run Code Online (Sandbox Code Playgroud)