6

I have a two servlets in my application and I want an object of class A to be injected to both the servlets, and I would also like the same ApplicationContext throughout the application i.e. both servlets as mentioned in the first answer of this question on SO: Spring injection Into Servlet

Now I went through many questions like these but couldnt find something exactly that matches my question. To explain better Ill write a rough code here:

public class servletOne extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }
}

public class servletTwo extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }
}

So above are the two servelts now in applicationContext.xml I want to pass an object to both these servlets so as per normal convention I want a functionality like this:

<bean id="servletFirst" class="mypackage.servletOne">
        <property name="message" ref="classObject" />


</bean>
<bean id="servletFirst" class="mypackage.servletTwo">
        <property name="message" ref="classObject" />


</bean>

<bean id="classObject" class="mypackage.classA">

    </bean>

I dont know if this is possible or not, I am new to spring and I have only basic knowledge of dependency Injection.

If anyone can help me with this I would really really appreciate it. This would clear a lot of my doubts and help me move forward in the process of learning Spring.

This is web.xml

    <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>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>servletOne</servlet-name>
        <servlet-class>mypackage.servletOne</servlet-class>
    </servlet>
<servlet>
        <servlet-name>servletTwo</servlet-name>
        <servlet-class>mypackage.servletTwo</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>servletOne</servlet-name>
        <url-pattern>/servletOne</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>servletTwo</servlet-name>
        <url-pattern>/servletTwo</url-pattern>
    </servlet-mapping>

    <session-config>
        <session-timeout>
            300
        </session-timeout>
    </session-config>
</web-app>
Community
  • 1
  • 1
Nick Div
  • 5,338
  • 12
  • 65
  • 127
  • It depends on how you are registering your Servlet beans with the Servlet container. – Sotirios Delimanolis Jan 10 '14 at 20:43
  • @SotiriosDelimanolis Could you please elaborate a little bit, i did not understand exactly what you are asking, is there any file or code that I can post that would clear your doubt? – Nick Div Jan 10 '14 at 20:48
  • You have two beans that extend the `HttpServlet` class. How are you using (or planning to use) those two beans? – Sotirios Delimanolis Jan 10 '14 at 20:52
  • @SotiriosDelimanolis I see that the answer that I have mentioned in my question is given by you only, but I dont where to write the code that you have posted in your answer because as i said i am new to spring and I would like the approach that you mentioned "Now all your servlets have access to the same ApplicationContext through the ServletContext attributes." but dont know how to pass the object and how to get same applicationContext throughout the application. – Nick Div Jan 10 '14 at 20:52
  • @SotiriosDelimanolis they are basically servlets so they will called from browser from an HTML page, I mean that is how I intend to call them – Nick Div Jan 10 '14 at 20:53
  • You need to first understand that servlets are managed by the Servlet container, typically registered through the deployment descriptor, ie. the web.xml file. You are declaring them as beans. Unless there is something you aren't showing us, they will not be used by the Servlet container. – Sotirios Delimanolis Jan 10 '14 at 20:56
  • @SotiriosDelimanolis I added the web.xml in the question, I have declared them in that web.xml – Nick Div Jan 10 '14 at 21:00

2 Answers2

16

You're mixing up two concepts: Servlets and Spring's ApplicationContext. Servlets are managed by your Servlet container, let's take Tomcat for example. The ApplicationContext is managed by Spring.

When you declare a Servlet in your deployment descriptor as

<servlet>
    <servlet-name>servletOne</servlet-name>
    <servlet-class>mypackage.servletOne</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servletOne</servlet-name>
    <url-pattern>/servletOne</url-pattern>
</servlet-mapping>

The Servlet container will create an instance of your mypackage.servletOne class, register it, and use it to handle requests. This is what it does with the DispatcherServlet which is the basis of Spring MVC.

Spring is an IoC container that uses ApplicationContext to manage a number of beans. The ContextLoaderListener loads the root ApplicationContext (from whatever location you tell it to). The DispatcherServlet uses that root context and must also load its own. The context must have the appropriate configuration for the DispatcherServlet to work.

Declaring a bean in the Spring context, like

<bean id="servletFirst" class="mypackage.servletOne">
        <property name="message" ref="classObject" />
</bean>

regardless of the fact that it is of the same type as the <servlet> declared in web.xml, is completely unrelated. The bean above has nothing to do with the <servlet> declaration in the web.xml.

As in my answer here, because the ContextLoaderListener puts the ApplicationContext it creates into the ServletContext as an attribute, that ApplicationContext is available to any Servlet container managed object. As such, you can override the HttpServlet#init(ServletConfig) in your custom HttpServlet classes, like so

@Override
public void init(ServletConfig config) throws ServletException {
   super.init(config);

   ApplicationContext ac = (ApplicationContext) config.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

   this.someObject = (SomeBean)ac.getBean("someBeanRef");
}

assuming that your root ApplicationContext contains a bean called someBeanRef.

There are other alternatives to this. This, for example.

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 1
    Now i understand that servlets cannot be instantiated the way i wrote it in ApplicationContext.xml, cool. I get that its the servlet container's responsibility to create their instance but I couldnt totally unserstand the second half of the answer. Why is applicationContext.xml declared in web.xml etc. basically first 14 lines in my web.xml – Nick Div Jan 10 '14 at 21:28
  • 1
    @kapil I didn't say `ApplicationContext` is declared in web.xml. I said that beans in the application context are (typically) unrelated to anything in the web.xml – Sotirios Delimanolis Jan 10 '14 at 21:30
  • yes yes i got that, but as you can see in web.xml: contextConfigLocation /WEB-INF/applicationContext.xml org.springframework.web.context.ContextLoaderListener dispatcher org.springframework.web.servlet.DispatcherServlet 2 Y dez linesin web.xml – Nick Div Jan 10 '14 at 21:33
  • sorry I pasted the web.xml in comments. But all I want to know is the significance of above lines in the web.xml and also if I go accprding to your answer do I have to declare : Override public void init(ServletConfig config) throws ServletException { super.init(config); ApplicationContext ac = (ApplicationContext) config.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); this.someObject = (SomeBean)ac.getBean("someBeanRef"); } in all my servlets – Nick Div Jan 10 '14 at 21:34
  • @kapilchhattani Those lines are there because they set up the basic stack for Spring MVC. And yes you would have to put that code in each `Servlet` implementation for which you want to use the `ApplicationContext`. But again, there are alternatives. – Sotirios Delimanolis Jan 10 '14 at 21:37
  • 1
    @kapilchhattani Consider looking into `HttpRequestHandlerServlet`. – Sotirios Delimanolis Jan 10 '14 at 21:39
  • I appreciate all the help that you have provided. I have one last question, once the request is sent from my browser first thing that gets hit is servletOne so how do I set attribute before that in the servletContext as you have done here: sce.getServletContext().setAttribute("applicationContext", ac); – Nick Div Jan 10 '14 at 21:44
  • 1
    @kapil In this case, you don't need to do that. The `ServletContextListener` is an interface that the Servlet container uses to initialize to `ServletContext`. The `ContextLoaderListener` is an implementation of that interface which already sets the `ApplicationContext` as an attribute in the `ServletContext`. It uses the key referenced by `WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE`, which you can use to retrieve it. – Sotirios Delimanolis Jan 10 '14 at 21:46
  • Oh my god what language is this, can you please explain this in simple words like a noob will understand and it is Ok if it is too much. I would understand. You have already done enough. – Nick Div Jan 10 '14 at 21:53
  • 1
    @kapilchhattani It's just a `static` variable in the `WebApplicationContext` class. – Sotirios Delimanolis Jan 10 '14 at 21:54
  • Ok so does this static variable get set because of contextConfigLocation /WEB-INF/applicationContext.xml So if I write contextConfigLocation /WEB-INF/kapil.xml will kapil.xml be the value of that static variable you just mentioned above – Nick Div Jan 10 '14 at 21:59
  • @Kapil Not exactly. The `ContextLoaderListener` will use the value of the `contextConfigLocation` context param to create an `ApplicationContext`. It will then get a reference to the `ServletContext` and do `ServletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, theApplicationContext)`. – Sotirios Delimanolis Jan 10 '14 at 22:01
  • Alright, sounds good. Thanks a lot for all the help, you have great knowledge and also a good way of explaining. I really appreciate the help. – Nick Div Jan 10 '14 at 22:04
-2

If you want to use @Autowired or set property via applicationContext.xml then annotate your class with @Controller annotation

Алексей
  • 1,847
  • 12
  • 15