Java @ServletContextListener中的自动连线

Java @ServletContextListener中的自动连线,java,spring,spring-mvc,Java,Spring,Spring Mvc,我有一个初始化应用程序 @Component public class InitApp implements ServletContextListener { @Autowired ConfigrationService weatherConfService; /** Creates a new instance of InitApp */ public InitApp() { } public void contextInitialized(ServletContextEvent

我有一个初始化应用程序

@Component
public class InitApp implements ServletContextListener {

@Autowired
ConfigrationService weatherConfService;

/** Creates a new instance of InitApp */
public InitApp() {
   }

public void contextInitialized(ServletContextEvent servletContextEvent) {
    System.out.println(weatherConfService);
   }
public void contextDestroyed(ServletContextEvent servletContextEvent) {
   }
}
和web.xml中的侦听器:

    <listener>
        <listener-class>com.web.Utils.InitApp</listener-class>
    </listener>

    <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

com.web.Utils.InitApp
org.springframework.web.context.ContextLoaderListener
服务打印-->为空 什么问题?

通过声明

<listener>
  <listener-class>com.web.Utils.InitApp</listener-class>
</listener>

请注意,Spring有一些非常复杂的
WebApplicationInitializer
自定义实现。你真的不需要自己直接实现它。这个想法保持不变,只是在继承层次结构的更深层。

正如其他人所说,这个侦听器通过web servlet(tomcat)上下文(而不是Spring容器)进行观察,并收到servlet启动/关闭的通知

因为它是由Spring容器外部的servlet创建的,所以它不是由Spring管理的,因此@Autowire成员是不可能的

如果将bean设置为托管@组件,那么Spring将创建实例,侦听器将不会向外部servlet注册

你不能两全其美

一种解决方案是删除Spring注释并从Spring应用程序上下文中手动检索您的成员,并以此方式设置您的成员


当我遇到同样的问题时,我想到了一些想法

第一个是使用Spring UTIL从侦听器中的Spring上下文检索bean:

例:

如果你只有一两颗豆子,这个方法就可以了。否则它会变得乏味。另一个选项是显式调用Spring的Autowire实用程序:

@WebListener
public class CacheInitializationListener implements ServletContextListener {

    @Autowired
    private CacheManager cacheManager;

    /**
     * Initialize the Cache once the application has started
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        try {
            cacheManager.init();
        } catch (Exception e) {
            // rethrow as a runtime exception
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // TODO Auto-generated method stub

    }
}

在这两种解决方案中需要注意的是,必须先加载Spring上下文,然后这两种解决方案中的任何一种才能工作。如果无法使用
@WebListener
定义侦听器顺序,请确保在
web.xml
中定义了Spring
ContextLoaderListener
,以强制首先加载它(在web描述符中定义的侦听器在通过注释定义的侦听器之前加载).

您应该在xml Spring配置中定义
ConfigurationService
,正如Nambari所指出的,或者,您应该将
组件扫描
放在包含
配置服务
的软件包上,并使用
@component
@service
对服务进行注释。您可以提供一个解决方法的示例吗?我很难理解
@Configuration
bean如何将一些东西注入到由容器管理的bean中。
@Config
bean如何获得容器bean的引用?@EricB。使用
ServletContainerInitializer
WebApplicationInitializer
您自己正在初始化和注册
ServletContextListener
。由于您还可以访问Spring
WebApplicationContext
,因此可以从中检索bean并将其交给侦听器。@EricB。(如果你想要一个完整的例子,你必须稍后再给我。)当然-我可以使用类似
webapplicationcontextils.getRequiredWebApplicationContext
的东西来检索应用程序上下文,然后从中获取bean,但我不确定这是否是你的意思。我从你的帖子中了解到,这可以通过Spring配置类完成,并将Spring bean推送到监听器中(而不是让监听器从Spring上下文中提取bean),我很想看看如何在Spring中操纵listener bean。
    public class InitApp implements ServletContextListener {

        private ConfigrationService weatherConfService;

        private static ApplicationContext   applicationContext  = new ClassPathXmlApplicationContext("classpath:web-context.xml");

        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            weatherConfService = applicationContext.getBean(ConfigrationService.class);
            System.out.println(weatherConfService);
        }

        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
        }
    }
@WebListener
public class CacheInitializationListener implements ServletContextListener {

    /**
     * Initialize the Cache Manager once the application has started
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        CacheManager cacheManager = WebApplicationContextUtils.getRequiredWebApplicationContext(
                sce.getServletContext()).getBean(CacheManager.class);
        try {
            cacheManager.init();
        } catch (Exception e) {
            // rethrow as a runtime exception
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // TODO Auto-generated method stub

    }
}
@WebListener
public class CacheInitializationListener implements ServletContextListener {

    @Autowired
    private CacheManager cacheManager;

    /**
     * Initialize the Cache once the application has started
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        try {
            cacheManager.init();
        } catch (Exception e) {
            // rethrow as a runtime exception
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // TODO Auto-generated method stub

    }
}
@WebListener
public class StartupListener implements ServletContextListener {

    @Autowired
    private MyRepository repository;

    @Override
    public void contextDestroyed(ServletContextEvent event) {
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        AutowireCapableBeanFactory autowireCapableBeanFactory = WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext()).getAutowireCapableBeanFactory();
        autowireCapableBeanFactory.autowireBean(this);

        repository.doSomething();
    }
}