6

I've got a Spring Boot where I've autoconfigured a Router bean. This all works perfect but it becomes a problem when I want to inject that bean into a custom servlet:

public class MembraneServlet extends HttpServlet {
    @Autowired
    private Router router;

    @Override
    public void init() throws ServletException {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        new HttpServletHandler(req, resp, router.getTransport()).run();
    }
}

This should be the way to go, but

SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);

won't autowire the Router because the WebapplicationContext is always null. The application is running in an MVC environment.

helpermethod
  • 59,493
  • 71
  • 188
  • 276

3 Answers3

5

Assuming you Spring Application Context is wired to the Servlet Context, you might want to pass ServletContext to SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext

public class MembraneServlet extends HttpServlet {

  @Autowired
    private Router router;

    @Override
    public void init() throws ServletException {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this, getServletContext());
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        new HttpServletHandler(req, resp, router.getTransport()).run();
    }
}
Stackee007
  • 3,196
  • 1
  • 26
  • 39
1

What about injecting 'Router' as constructor parameter.

So you would have this:

public class MembraneServlet extends HttpServlet {

    private Router router;

    public MembraneServlet(Router router){
        this.router = router;
    }

    @Override
    public void init() throws ServletException {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        new HttpServletHandler(req, resp, router.getTransport()).run();
    }
}

then you can programatically create servlet registration like this:

@Bean
public ServletRegistrationBean membraneServletRegistrationBean(){
    return new ServletRegistrationBean(new MembraneServlet(),"/*");
}
bilak
  • 4,526
  • 3
  • 35
  • 75
  • That won't work because the HttpServlet is not instantiated by Spring. – helpermethod Jun 14 '17 at 08:28
  • sorry I've copied the OP's code and didn't removed the `SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);` which is unnecessary if only the `Router` bean is needed. – bilak Jun 14 '17 at 08:51
1

Embedded server

You can annotate with @WebServlet your servlet class:

@WebServlet(urlPatterns = "/example")
public class ExampleServlet extends HttpServlet 

And enable @ServletComponentScan on base class:

@ServletComponentScan
@EntityScan(basePackageClasses = { ExampleApp.class, Jsr310JpaConverters.class })
@SpringBootApplication
public class ExampleApp 

But injection with @ServletComponentScan will work only with embedded server:

Enables scanning for Servlet components (filters, servlets, and listeners). Scanning is only performed when using an embedded web server.

More info: The @ServletComponentScan Annotation in Spring Boot

External server

When using external server, mark HttpServlet class as @Component:

@Component
public class ExampleServlet extends HttpServlet 

And create configuration class:

@Configuration
@ComponentScan(value = "com.example.servlet.package")
public class ServletConfig {

    @Autowired
    private ExampleServlet exampleServlet;

    @Bean
    public ServletRegistrationBean resetServletRegistrationBean(){
        return new ServletRegistrationBean(exampleServlet, "/example");
    }
}
Justinas Jakavonis
  • 8,220
  • 10
  • 69
  • 114