Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot: Inject Bean into HttpServlet

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.

like image 455
helpermethod Avatar asked Apr 27 '17 09:04

helpermethod


3 Answers

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();
    }
}
like image 94
Stackee007 Avatar answered Nov 03 '22 00:11

Stackee007


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(),"/*");
}
like image 33
bilak Avatar answered Nov 03 '22 00:11

bilak


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");
    }
}
like image 22
Justinas Jakavonis Avatar answered Nov 03 '22 01:11

Justinas Jakavonis