@Autowired在ServletContextListener中
我hava aclass InitApp
@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中的监听器:
com.web.Utils.InitApp org.springframework.web.context.ContextLoaderListener
confService打印 – > null有什么问题?
当我遇到同样的问题时,我想到了几个想法。
第一个是使用Spring utils从侦听器中的Spring上下文中检索bean:
例如:
@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 } }
如果您只有一个或两个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描述符中定义的侦听器在@WebListener
定义的侦听器之前加载)。
通过声明
com.web.Utils.InitApp
在您的web.xml中,您告诉容器初始化并注册InitApp
实例。 因此,该对象不是由Spring管理的,你不能@Autowired
任何东西。
如果您的应用程序上下文设置为组件扫描com.web.Utils
包,那么您将拥有一个未注册为容器侦听器的InitApp
bean。 因此,即使你的其他bean将是@ @Autowired
,servlet容器也不会命中它。
这是权衡。
如果对Servlet 3.0使用ServletContainerInitializer
或WebApplicationInitializer
进行编程配置,则有一些解决方法。 你不会使用@Autowired
,你只需要用于设置实例的setter / getter。
这是一个例子
class SpringExample implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { WebApplicationContext context = ...; SomeBean someBean = context.getBean(SomeBean.class); CustomListener listener = new CustomListener(); listener.setSomeBean(someBean); // register the listener instance servletContext.addListener(listener); // then register DispatcherServlet and ContextLoaderListener, as appropriate ... } } class CustomListener implements ServletContextListener { private SomeBean someBean; public SomeBean getSomeBean() { return someBean; } public void setSomeBean(SomeBean someBean) { this.someBean = someBean; } @Override public void contextInitialized(ServletContextEvent sce) { // do something with someBean } @Override public void contextDestroyed(ServletContextEvent sce) { } }
请注意,Spring有一些非常复杂的WebApplicationInitializer
自定义实现。 你真的不需要自己直接实现它。 这个想法保持不变,只是在inheritance层次结构中更深层次。
正如其他人所说,这个监听器通过web servlet(tomcat)上下文(不是Spring容器)进行观察,并被告知servlet启动/关闭。
由于它是由Spring容器外部的servlet创建的,因此不受Spring管理,因此@Autowire成员是不可能的。
如果将bean设置为托管的@Component,则Spring将创建实例,并且侦听器不会注册外部servlet。
你不可能两种方式..
一种解决方案是删除Spring注释并从Spring Application上下文中手动检索您的成员,并以这种方式设置您的成员。
即
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 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(); } }