`
auauau
  • 浏览: 172169 次
社区版块
存档分类
最新评论

Reloading a Spring Web Application

阅读更多
It took me a while, but I got a refreshable Spring web context to work! It wasn't too hard, but I was hoping it would be easier.

The biggest problem I faced was that the venerable DispatcherServlet initializes member variables based on the ApplicationContext that it creates. I created a hacky subclass to get around this problem:

public class RefreshableDispatcherServlert extends DispatcherServlet {

    public static final String SERVLET_ATTRIBUTE_NAME = RefreshableDispatcherServlert.class
            .getName()
            + "_SERVLET_ATTRIB";

    protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache)
            throws Exception {
        RequestContextHolder.getRequestAttributes().setAttribute(getClass().getName(), this,
                RequestAttributes.SCOPE_REQUEST);
        return super.getHandler(request, cache);
    }
}

I then use that dispatcher servlet in a "refreshing" controller:
public class RefreshingController implements Controller, ApplicationContextAware {

    private ApplicationContext applicationContext;

    private Log logger = LogFactory.getLog(getClass());

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
        refresh(response, request, configurableApplicationContext);
        return null;
    }

    private void refresh(HttpServletResponse response, HttpServletRequest request,
            ConfigurableApplicationContext context) throws IOException, ServletException {
        long start = System.currentTimeMillis();

        log(response, "refreshing context");

        refreshParent(response, request, context, start);

        refreshServlet();

        log(response, "refreshed servlet in " + (System.currentTimeMillis() - start) + " ms.");
    }

    private void refreshParent(HttpServletResponse response, HttpServletRequest request,
            ConfigurableApplicationContext context, long start) throws IOException {
        ConfigurableApplicationContext parent = (ConfigurableApplicationContext) context
                .getParent();

        if (parent != null && "true".equals(request.getParameter("reloadParent"))) {
            parent.refresh();
            log(response, "refreshed parent in " + (System.currentTimeMillis() - start) + "ms");
        }
    }

    private void refreshServlet() throws ServletException {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        String key = RefreshableDispatcherServlert.SERVLET_ATTRIBUTE_NAME;

        DispatcherServlet servlet = (DispatcherServlet) requestAttributes.getAttribute(key,
                RequestAttributes.SCOPE_REQUEST);

        servlet.init();

    }

    private void log(HttpServletResponse response, String string) throws IOException {
        log(string, response.getWriter());
    }

    private void log(String string, PrintWriter writer) {
        logger.info(string);
        writer.write(string);
        writer.write("");
        writer.flush();
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}


It's hacky but it works for my needs . I prevously would have to bounce my Web's Fear application context which takes 2-5 minutes. It also saves JSP recompilations which take quite a while in our setup... The DispatcherServlet reloading taks 10 seconds. The top level app context + the DispatcherServlet context takes 30 seconds.

We have a huge system with lots of dependencies and a beast of a development environment. I'll be thinking about modularization and speed ups, including some potentially neat Spring tricks...

来自:http://www.jroller.com/Solomon/entry/reloading_a_spring_web_application

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics