在main方法中初始化spring环境,注入bean

时间:2022-11-15 21:20:33
public static void main(String[] args) {

    LOGGER.info("==启动APP日志队列程序=="); SpringUtils.getBean(UserAppLogConsumerListener.class); }

  一开始我是使用自定义的spring工具类的getBean方法进行初始化,但是存在问题:配置文件中用有引用UserAppLogConsumerListener这个bean,导致报错expected single matching bean but found 2

Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.cdd.rabbitmq.consume.listener.UserAppLogConsumerListener' available: expected single matching bean but found 2: userAppLogConsumerListener,userAppReceiver
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1039)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:339)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:334)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1107)
    at com.cdd.core.utils.SpringUtils.getBean(SpringUtils.java:28)
    at com.cdd.rabbitmq.consume.Main.main(Main.java:23)

  然后换了一种方式,直接根据配置文件加载ApplicationContext,成功

public static void main(String[] args) {

    LOGGER.info("==启动APP日志队列程序==");
//    SpringUtils.getBean(UserAppLogConsumerListener.class);
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
}

   继续找了一下资料,发现Spring在非web应用中关闭IoC容器需要在JVM里注册一个“关闭钩子”(shutdown hook),这样会确保你的Spring IoC容器被恰当关闭,以及所有由单例持有的资源都会被释放。

  为了注册“关闭钩子”,你只需要简单地调用在org.springframework.context.support.AbstractApplicationContext实现中的registerShutdownHook()方法即可。

  对于关闭钩子和start()方法的作用还不太理解,在网上找的介绍如下:

  关闭钩子网上介绍的作用:Java Runtime注册的ShutdownHook在JVM进程正常关闭(操作系统正常关闭,用户调用System.exit(0), kill, Ctrl+C等)执行,Spring注册这个旨在正常关闭的时候关闭(代码中的doClose())容器。关闭容器的时候,会释放所有容器管理Bean,同时如果容器管理Bean声明了销毁回调方法也会执行(典型的就是数据库连接池的关闭,执行线程池的关闭等)以释放资源。不过kill -9,拔电等不在此讨论范围。

  start()方法的作用在于,启动某个组件,如果该组件已经启动则不抛出异常,如果启动的是某个container,则会将启动信号扩散至该容器内部的所有组件。

  最终代码:

public static void main(String[] args) {

    LOGGER.info("==启动APP日志队列程序==");
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    context.registerShutdownHook();
    context.start();
}