Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Autowired in Servlet

I am using Spring framework (2.5.4) in my app with Load time weaving and everything works fine everywhere (in Spring beans, in non-Spring entities), except when I try to autowire field in a servlet annotated as @Configurable, then I get a nice NullPointerException...


@Configurable(dependencyCheck=true)
public class CaptchaServlet extends HttpServlet{
    @Autowired
    private CaptchaServiceIface captchaService;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    //    ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
    //    captchaService = (CaptchaServiceIface) ctx.getBean("captchaService");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Captcha c = captchaService.getCatpcha();
        req.getSession().setAttribute("captchaAnswer", c.getAnswer());
        resp.setContentType("image/png");
        ImageIO.write(c.getImage(), "png", resp.getOutputStream());
    }
}

<context:load-time-weaver/>
<context:spring-configured/>
<context:component-scan base-package="cz.flexibla2" />

Any suggestions about what am I doing incorrectly?

Thanks.

like image 979
malejpavouk Avatar asked Nov 15 '10 12:11

malejpavouk


2 Answers

This is likely because the Servlet is being instantiated and initialized by the servlet container, before the Spring context is being initialized, and it's the Spring context which handles the load-time weaving.

Is your <context:load-time-weaver/> stuff being handle inside the servlet Spring context/ or at the webapp-level? The former almost certainly won't work (for the reasons specified above), but a webapp-level config might work (using ContextLoaderListener).

like image 121
skaffman Avatar answered Oct 15 '22 06:10

skaffman


See also mailing list discussion and bug report at https:// bugs.eclipse.org/bugs/show_bug.cgi?id=317874 . I agree that intuitively the @Configurable annotation on the servlet should be enough to indicate to the spring framework that the servlet when instantiated will be configured by spring, when using <context:spring-configured/>. I have also observed that the desired behavior is achievable when using the -javaagent:/path/to/aspectjweaver.jar instead of spring-instrument*.jar or spring-agent.jar. Please raise an issue with Spring Jira at https:// jira.springframework.org/browse/SPR. I believe that the problem may be that the servlet class - not an instance of the servlet, but the class itself - is loaded before the spring ContextLoaderListener is called, thus the spring framework does not have a chance to instrument the servlet class before it is loaded.

The spring instrumentation for load-time-weaving appears to be based on being able to transform class bytecode before it is loaded. If the servlet container is holding onto an instance of the Class object that was obtained before it was transformed by spring, then it (the servlet container) would not be able to produce instances of the transformed class, nor would spring be able to instrument instances created using the factory methods on that Class object.

like image 3
Larry Chu Avatar answered Oct 15 '22 06:10

Larry Chu