java ServletContextListener 中的@Autowired
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17656046/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
@Autowired in ServletContextListener
提问by abdelhady
i hava aclass InitApp
我有一个类 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) {
}
}
and listener in web.xml:
和 web.xml 中的侦听器:
<listener>
<listener-class>com.web.Utils.InitApp</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
the confService print --> null what the problem?
confService 打印 --> null 有什么问题?
回答by Eric B.
A couple of ideas came to me as I was having the same issue.
当我遇到同样的问题时,我想到了一些想法。
First one is to use Spring utils to retrieve the bean from the Spring context within the listener:
第一个是使用 Spring utils 从侦听器内的 Spring 上下文中检索 bean:
Ex:
前任:
@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
}
}
This works fine if you only have one or two beans. Otherwise it can get tedious. The other option is to explicitly call upon Spring's Autowire utilities:
如果你只有一两个豆子,这很好用。否则它会变得乏味。另一种选择是显式调用 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
}
}
The caveat in both these solutions, is that the Spring context must by loaded first before either of these can work. Given that there is no way to define the Listener order using @WebListener
, ensure that the Spring ContextLoaderListener
is defined in web.xml
to force it to be loaded first (listeners defined in the web descriptor are loaded prior to those defined by annotation).
这两种解决方案的警告是,必须先加载 Spring 上下文,然后才能工作。鉴于无法使用 定义侦听器顺序@WebListener
,请确保ContextLoaderListener
定义Springweb.xml
以强制首先加载它(在 Web 描述符中定义的侦听器在注解定义的侦听器之前加载)。
回答by Sotirios Delimanolis
By declaring
通过声明
<listener>
<listener-class>com.web.Utils.InitApp</listener-class>
</listener>
in your web.xml, you're telling your container to initialize and register an instance of InitApp
. As such, that object is not managed by Spring and you cannot @Autowired
anything into it.
在您的 web.xml 中,您告诉您的容器初始化和注册InitApp
. 因此,该对象不是由 Spring 管理的,您不能对其进行@Autowired
任何操作。
If your application context is set up to component-scan the com.web.Utils
package, then you will have a InitApp
bean that isn't registered as a Listener with the container. So even though your other bean will be @Autowired
, the servlet container won't ever hit it.
如果您的应用程序上下文设置为组件扫描com.web.Utils
包,那么您将拥有一个InitApp
未注册为容器的侦听器的bean。因此,即使您的另一个 bean 将是@Autowired
,servlet 容器也永远不会命中它。
That is the trade-off.
这就是权衡。
There are workarounds to this if you use programmatic configuration with a ServletContainerInitializer
or a WebApplicationInitializer
for servlet 3.0. You wouldn't use @Autowired
, you would just have setter/getter that you would use to set the instance.
如果您在 servlet 3.0 中使用带有 aServletContainerInitializer
或 a 的编程配置,则有解决方法WebApplicationInitializer
。您不会使用@Autowired
,您只会使用用于设置实例的 setter/getter。
Here's an example
这是一个例子
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) {
}
}
Note that Spring has some custom implementation of WebApplicationInitializer
that are quite sophisticated. You really shouldn't need to implement it directly yourself. The idea remains the same, just deeper in the inheritance hierarchy.
请注意,Spring 有一些WebApplicationInitializer
非常复杂的自定义实现。您真的不需要自己直接实现它。这个想法保持不变,只是在继承层次结构中更深。
回答by Oliver
@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();
}
}
回答by user3805223
As others have said this listener observes by the web servlet(tomcat) context (Not the Spring Container) and is notified of servlet startup/shutdown.
正如其他人所说,此侦听器通过 web servlet(tomcat) 上下文(不是 Spring 容器)进行观察,并在 servlet 启动/关闭时收到通知。
Since it is created by the servlet outside of the Spring container it is not managed by Spring hence @Autowire members is not possible.
由于它是由 Spring 容器外部的 servlet 创建的,因此它不受 Spring 管理,因此 @Autowire 成员是不可能的。
If you setup your bean as a managed @Component then Spring will create the instance and the listener wont register with the external servlet.
如果您将 bean 设置为托管的 @Component,那么 Spring 将创建实例并且侦听器不会向外部 servlet 注册。
You cannot have it both ways..
你不能同时拥有它..
One solution is the remove the Spring annotations and manually retrieve your member from the Spring Application context and set your members that way.
一种解决方案是删除 Spring 注释并从 Spring Application 上下文中手动检索您的成员并以这种方式设置您的成员。
ie
IE
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) {
}
}