偶然看到一个Servlet的Filter实现,在doFilter方法中,发现有对Spring容器的访问,用法如下:
[code]
XxxService xxxService = SpringContextHolder.getApplicationContext().getBean("xxxService", XxxService.class);
[/code]
其中有个SpringContextHolder,看名称就能大概猜出来它的意思,里面保持一个Spring的Context,调用方式上看,是静态的。
实际代码也是这么实现的:
[code]
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
}
[/code]
整个的调用顺序是这样的:
[code]
1、服务启动,初始化SpringContextHolder,Spring的ApplicationContext注入到SpringContextHolder中。
2、有请求需要此Filter处理时,通过SpringContextHolder拿到Spring的容器,从中取出所需的bean。
[/code]
实际上用Spring还有一种更简单的做法,也是比较中规中矩的,不需要SpringContextHolder,使用原生的WebApplicationContext就可以从doFilter方法的request中取到:
[code]
ServletContext serveletContext = request.getSession().getServletContext();
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(serveletContext);
XxxService xxxService = springContext.getBean("xxxService", XxxService.class);
[/code]
以上这种方式使用的前提是在web.xml配置了ContextLoaderListener
[code]
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
[/code]
如果没有配置这个ContextLoaderListener,只配置了DispatcherServlet,如下
[code]
<servlet>
<servlet-name>XXXX</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>XXXX</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
[/code]
使用默认的就不成了:WebApplicationContextUtils.getWebApplicationContext(serveletContext);
因为默认从servletContext中取的key是常量:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
实际上只使用DispatcherServlet用的key是:FrameworkServlet.SERVLET_CONTEXT_PREFIX + getServletName();即org.springframework.web.servlet.FrameworkServlet.CONTEXT.XXXX
可使用以下方法获取,只是稍麻烦了一点。遍历取相应类型的实例
[code]
ServletContext servletContext = request.getSession().getServletContext();
WebApplicationContext springContext = null;
Enumeration<?> names = servletContext.getAttributeNames();
while (names.hasMoreElements()) {
String servletName = names.nextElement().toString();
Object obj = servletContext.getAttribute(servletName);
if (obj instanceof WebApplicationContext) {
springContext = (WebApplicationContext) obj;
System.out.println(servletName);
break;
}
}
if (webAppContext != null) {
XxxService xxxService = springContext.getBean("xxxService", XxxService.class);
}
[/code]