HTTP 代理
如果您的 Tomcat 服务器前面有某种代理(如apache或nginx),我相信可以将其配置为将 404 转换为不同的状态代码和错误页面。如果您没有任何代理或希望解决方案保持独立:
自定义 Spring 加载器和 servlet 过滤器
由于您使用的是 Spring,我猜您正在使用ContextLoaderListener
in引导它web.xml
:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
此类负责引导 Spring,这是在大多数情况下导致应用程序启动失败的步骤。只需扩展该类并吞下任何异常,使其永远不会到达 servlet 容器,因此 Tomcat 不会认为您的应用程序部署失败:
public class FailSafeLoaderListener extends ContextLoaderListener {
private static final Logger log = LoggerFactory.getLogger(FailSafeLoaderListener.class);
@Override
public void contextInitialized(ServletContextEvent event) {
try {
super.contextInitialized(event);
} catch (Exception e) {
log.error("", e);
event.getServletContext().setAttribute("deployException", e);
}
}
}
代码非常简单——如果 Spring 初始化失败,记录异常并将其全局存储在ServletContext
. 新加载器必须替换旧加载器web.xml
:
<listener>
<listener-class>com.blogspot.nurkiewicz.download.FailSafeLoaderListener</listener-class>
</listener>
现在您所要做的就是在全局过滤器中从 servlet 上下文中读取该属性,并在应用程序无法启动 Spring 时拒绝所有请求:
public class FailSafeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void destroy() {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Exception deployException = (Exception) request.getServletContext().getAttribute("deployException");
if (deployException == null) {
chain.doFilter(request, response);
} else {
((HttpServletResponse) response).sendError(500, deployException.toString());
}
}
}
将此过滤器映射到所有请求(或者可能只是控制器?):
<filter-mapping>
<filter-name>failSafeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
解决方案可能不是您想要的,但我给您一个通用的、有效的示例。