2

I have a project with a few old HTTPServlets, I would like a way to manage the creation/life-cycle of the Servlet in Spring so I can do a few things like DI and pass in database objects through Spring/Hibernate integration.

First I have setup the Spring application context in web.xml as follows;

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Next I have my servlet definition in web.xml;

<servlet>
    <servlet-name>oldHttpServlet</servlet-name> 
    <display-name>oldHttpServlet</display-name>
    <servlet-class>com.package.MyServlet</servlet-class>
</servlet>

In my Spring application-context.xml I would like to make some bean def as follows;

<bean id="oldHttpServlet" class="com.package.MyServlet"></bean>

I think the above I need to implement some interface within my servlet, keep the bean definition as above in the Spring app-context.xml and then make a change to the servlet definition in the web.xml... I'm not sure what is the simplest change to make as there is some inheritance to worry about on the MyServelet.java side, which looks like this;

class MyServlet extends MyAbstractServlet{
  void doStuff(){
     //YOu know...
  }
}

And MyAbstractServlet;

class MyAbstractServlet extends HttpServlet{
  doPost(){
     //Some post implementation here...
  }
}

What is the best way to wrap MyServlet in Spring and have it loaded from there rather than being instantiated via web.xml?

I'm assuming the best way would be to use Springs HttpRequestHandler and then use the HttpRequestHandlerServlet in the web.xml in place of the current servlet. However I'm not sure how I go about implementing the HttpRequestHandler interface to work with the existing doPost() stuff in the myAbstractServlet...

Andrei Sfat
  • 8,440
  • 5
  • 49
  • 69
NightWolf
  • 7,694
  • 9
  • 74
  • 121
  • 2
    You cant create servlets in Spring, it's the container who decides when and how many sevlet instances to create, you can manualy autowire the servlet fields though http://stackoverflow.com/questions/467235/access-spring-beans-from-a-servlet-in-jboss – Boris Treukhov Jan 17 '13 at 08:23

3 Answers3

5

If you need to inject dependencies into a servlet than I would go with Spring's HttpRequestHandlerServlet. You create an implementation of HttpRequestHandler (it has a method:

public void handleRequest(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException;

that you need to implement - it is the equivalent of what you'd have in a doGet / doPost. The instance of all your HttpRequestHandler implementatins should be handled by spring (set up an annotation driven config and annotate it with, say, @Component) or use an XML config to set up those beans.

In your web.xml create the mapping for HttpRequestHandlerServlet. If you name the servlet the same as you did your HttpRequestHandler then Spring will make HttpRequestHandlerServlet automatically handle the request with the matching HttpRequestHandler.

Since HttpRequestHandler is a Spring bean, you can make Spring inject all the services you need into it.

If you still do not want to use HttpRequestHandler in lieu of Servlets than all that is left is some "programming judo", like retrieving WebApplicationContext with Spring utils and getting beans from there by a "per name" basis. Servlets are not instantiated by Spring so it cannot manage them. You would have to create a base class for your servlets and manage the DI as an initialization step yourself.

The code would look like this (inside a servlet):

WebApplicationContext webContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
CertainBeanClass bean = (CertainBeanClass) webContext.getBean("certainBean");

[EDIT] Indeed, as one of the commenters suggested, there IS one more option. It still requires you to do a manual setup in your servlets init method though. Here is how this would look like:

public void init(ServletConfig config) {
    super.init(config);
    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}

You may also try your luck with @Configurable annotation on Servlet with weaving, but this might or might not work (I think Servlet might get initialized before Spring context is set up, so it still won't have the possibility to do its magic).

theadam
  • 3,961
  • 4
  • 25
  • 41
  • This is what I was thinking... But how could I keep my current doGet/doPost code and just wrap it in handleRequest..? I.e. HandleRequest is a wrapper which calls the doPost etc methods? – NightWolf Jan 17 '13 at 09:05
  • If you really HAVE TO reuse your old servlets then you can create a spring managed instance of the servlet and invoke it from handleRequest but I think this is the same amount of work as refactoring the servlets to become HttpRequestHandlers. PS. are you sure you do not want to use an MVC framework? Spring MVC feels very lightweight! If Spring MVC is too heavy than maybe so is Spring - you might look into Guice (by Google) - it integrates with pure servlets very easily. – theadam Jan 17 '13 at 10:53
  • Thanks for the edit! This is the way I did it as pointed out in @Boris Treukhov comment. Thanks. – NightWolf Jan 21 '13 at 01:14
1

The ideal use of Servlet should be as Controller and underlying container manages its life cycle so we don't need Spring to manage its instance

so I can do a few things like DI and pass in database objects through Spring/Hibernate integration.

You should never have dependency of Servlet in your dao/services, Your servlet should be calling services which is perfectly suitable to manage with Spring DI context

jmj
  • 237,923
  • 42
  • 401
  • 438
  • I'm not sure what you mean here. I want to @Autowire things (services) within the MyServlet, to do this auto wiring I need to make Spring aware of the MyServlet instance... Can I do this without re-writing half the server core, i.e. by wrapping it up somehow? – NightWolf Jan 17 '13 at 08:39
  • I've answered with the suggestion on how to solve your problem. You would need to migrate your servlets to become HttpReqestHandlers, but the signature is the same. There is no Spring-way on doing this on Servlets themselve. – theadam Jan 17 '13 at 08:41
  • 1
    Yes you could do it by making a ServiceLocator which reads bean from spring context and returns it – jmj Jan 17 '13 at 08:41
  • Are you using raw servlet or you are using SpringMVC framework over servlet ? – jmj Jan 17 '13 at 08:42
  • @Jigar Joshi - Do you have an example of such as ServiceLocator – NightWolf Jan 17 '13 at 09:10
  • 1
    `SpringBeanAutowiringSupport.autowire(this, config.getServletContext())` inside `init(config)` has stopped working? :D Or am I missing something – Boris Treukhov Jan 17 '13 at 09:27
0

regarding SpringBeanAutowiringSupport, note from the javadoc:

NOTE: If there is an explicit way to access the ServletContext, prefer such a way over using this class. The WebApplicationContextUtils class allows for easy access to the Spring root web application context based on the ServletContext.

Den Roman
  • 548
  • 7
  • 10