I am familiar with the Spring Framework and have done some work in it.
In one of my interviews, I was asked "there is a web application deployed in Apache Tomcat; tell me how does the "Tomcat container" (used for servlets) interact with "Spring IoC container" (used for Spring beans)?"
I couldn't understand what the interviewer meant by that and was left speechless. Can someone please clarify what this question was about and what a reasonable answer to it might be?
A spring web-app will define a Spring Dispatcher Servlet in its config, the apache tomcat container will initialise this servlet, the dispatcher servlet in turn initialises the application context. There is no direct interaction between the tomcat container and the Spring IOC container.
There are two primary aspects of linking Spring with Servlets. First you have to load a Spring application context, and second you need to expose those Spring-loaded objects to the Servlet. There are many ways to do this, and frameworks like CXF have built-in support for Spring.
But one of the most basic mechanisms is to use a ContextLoaderListener to load the application context and a HttpRequestHandlerServlet to initialize the servlet.
Here's a simple example:
web.xml:
<web-app>
...
<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>servletBean</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
...
</web-app>
And in /WEB-INF/applicationContext.xml:
<beans>
..
<!-- Note: YourServletClass must implement HttpRequestHandler -->
<bean id="servletBean" name="servletBean" class="yournamespace.YourServletClass">
...
</bean>
...
</beans>
Spring apps declare a DispatcherServlet as part of the application configuration. The DipatcherServlet is a child class of HttpServlet and hence represents the servlet for the container. The DispatcherServlet also creates a WebApplicationContext. Spring maintains an IOC container for each WebApplicationContext (there can be multiple servlets in an app). There can also be a root ApplicationContext, which is created by the ContextLoaderListener. The root ApplicationContext is a parent of all WebApplicationContext(s) in a web app. The IOC container of ApplicationContext is available to all WebApplicationContext(s).
The ServletContext remains the single mode of interaction for all web containers.
Related
I am just starting out trying to see what spring flow is about.This book that i have is describing how i have to configure the dispathcer-servlet.xml and create some flows in there.
Problem is i cannot find this dispatcher-servlet.xml file in my java spring application to start the configuration.Where is it?
I searched on here and on google but i only find people who already have n dispatcher-servlet.xml file and they are asking how to configure it.
Any help would be greatly appreciated!
You don't need dispatcher-servlet.xml to configure DispatcherServlet. It's just a default name Spring will look for if not defined. You can define config in contextConfigLocation init-param when defining DispatcherServlet in web.xml. Or, if you have single DispatcherServlet, you can use global spring xml configuration. If you have a working java spring application, look for
<context-param>
<param-name>contextConfigLocation</param-name>
...
</context-param>
or
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
...
</servlet>
in your web.xml
If you don't find it in web.xml, you will have to configure it yourself. I also think that the book might be for webflow 1.x. Try using official Spring Webflow reference, it's a good starting point, and is up-to-date:
https://docs.spring.io/spring-webflow/docs/current/reference/html/
Specifically, for Dispatcher servlet configuration look at this chapter:
https://docs.spring.io/spring-webflow/docs/current/reference/html/spring-mvc.html#spring-mvc-config-web.xml
I spent few days fixing bugs in my Spring project. For really long time, my main problems in error log were:
Bean already exists
I have got two files:
WEB-INF/myproject-servlet.xml
WEB-INF/web.xml
in first one, I can put following input (let's assume I have got an application to manage animals in zoo):
<context:component-scan base-package="com.my.package.animals" />
with that (as well as I understand) we are enabling Spring beans auto-discovery. So now, when we run our application, Spring will take all classes from this package, later it will go through all config files in resources directory and will inititliaze all beans (placed in config files, which are associated with a given package).
The second one, web.xml includes lines like this
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myproject-servlet.xml</param-value>
</context-param>
I can also put path to my config files, for instance:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:animals-config.xml</param-value>
</context-param>
So now, I have 'auto-detecting' in myproject-servlet.xml and I have got context-param in web.xml for the same objects.
My question is, is it possible, that errors "Bean already exists" are coming from this? I am almost sure that yes, I checked all beans ids and there is no duplicates.
So I have another question. What is a good approach of doing that? When I create new config file, where I should inform my application about that? In myproject-servlet.xml or web.xml. I really need to clean up my application and I will start with that.
I checked some examples and people rather do not put more than one <context-param> in web.xml file Simple example
Thank you in advance
Ok, I am really close to solve my problem.
Let's assume I have got two packages:
com.my.pckg.a
com.my.pckg.b
with classes
com.my.pckg.a.ClassA
com.my.pckg.b.ClassB
I added in myproject-servlet.xml following line:
<context:component-scan base-package="com.my.pckg.a" />
I have got a config file myconfig.xml and inside I have got beans based on classes ClassA and ClassB.
Let's say we have got beans with ids as follows:
ClassA: ida1, ida2
ClassB: idb1, idb2
So, I am running my jetty server and the question is:
Which beans will be initialized? I declared only package com.my.pckg.a, so from myconfig.xml, spring should load only ida1 and ida2 but this file includes also beans for another class.
So finally... ?
Finally, I suppose I find a problem. In web.xml file I have got a line:
<context:component-scan base-package="com.dirty.pckg" />
in this package I have got a class DirtyClass with #Controller annotation. One of the fields of this class is:
private static ApplicationContext context = new ClassPathXmlApplicationContext("dirty-config.xml");
So, when my application is getting up, Spring takes DirtyClass (because it has #) and maps it. Because os static modifier of context it triggers reading dirty-config.xml. That's way I could not understand why my code behaves in strange way.
The web.xml file is the configuration of your web application. It is not related to Spring.
The contextConfigLocation context-param is the one spring listener use to search for Spring configuration files. It is spring related.
You can have multiple spring configuration files that you register in your web.xml but these files must not define the same bean (bean id must be different). You can also have only one spring configuration file that will it self include other configuration files as described here : http://www.mkyong.com/spring/load-multiple-spring-bean-configuration-file/
Answer to the other question :
When you added the component scan, you ask spring to scan the package com.my.pckg.a for annotation like #Service, #Component, ... The component scan is not a filter for the rest of the configuration it is a configuration itself. So the fact that you added component scan, will not change the behaviour of myconfig.xml. Both ida1, ida2 and idb1, idb2 will be instanciated.
I don't really get what you are trying to accomplished with your configuration files. Maybe if you explain your needs, we could help you set up the right config for you.
web.xml is configuration file. It has classes(like listeners, filters,filter-mapping, servlet,servlet-mapping), resources and configuration(like context param, diplayname, error-page, session-config) of the application and how the web server uses them to handle web requests. When the web server receives a request for the application, it uses web.xml to map the URL of the request to the code that is supposed to handle the request.
Coming to what should be in web.xml and what should be in myproject-servlet.xml:
1)In Spring, ApplicationContext can be hierarchical. One ApplicationContext can have multiple child ApplicationContexts and can only have one parent. Beans in child ApplicationContext can access the beans in parent.
2)DispatcherServlet dispatches requests to handlers(controllers), with configurable handler mappings, view resolution configuration(what view template you use for the application for example jsp).
Keeping the two points in mind, our web.xml should be like:
<!--Root web application context(Parent context) - beans for service or persistence layer should be in this -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:service-layer-beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<!--DispatcherServlet loads its configuration into its own context(chile context) and refers Root web application context as a parent, so it have access to beans in parent context and can override it but not vice versa.-->
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myproject-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
A standard spring web application (created by Roo or "Spring MVC Project" Template) create a web.xml with ContextLoaderListener and DispatcherServlet. Why do they not only use the DispatcherServlet and make it to load the complete configuration?
I understand that the ContextLoaderListener should be used to load the stuff that is not web relevant and the DispatcherServlet is used to load the web relevant stuff (Controllers,...). And this result in two contexts: a parent and a child context.
Background:
I was doing it this standard way for several years.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Handles Spring requests -->
<servlet>
<servlet-name>roo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
This often caused problems with the two contexts and the dependencies between them. In the past I was always able to find a solution, and I have the strong feeling that this makes the software structure/architecture always better. But now I am facing a problem with the events of the both contexts.
-- However this makes my rethink this two context pattern, and I am asking myself: why should I bring myself into this trouble, why not loading all spring configuration files with one DispatcherServlet and removing the ContextLoaderListener completely. (I still will to have different configuration files, but only one context.)
Is there any reason not to remove the ContextLoaderListener?
In your case, no, there's no reason to keep the ContextLoaderListener and applicationContext.xml. If your app works fine with just the servlet's context, that stick with that, it's simpler.
Yes, the generally-encouraged pattern is to keep non-web stuff in the webapp-level context, but it's nothing more than a weak convention.
The only compelling reasons to use the webapp-level context are:
If you have multiple DispatcherServlet that need to share services
If you have legacy/non-Spring servlets that need access to Spring-wired services
If you have servlet filters that hook into the webapp-level context (e.g. Spring Security's DelegatingFilterProxy, OpenEntityManagerInViewFilter, etc)
None of these apply to you, so the extra complexity is unwarranted.
Just be careful when adding background tasks to the servlet's context, like scheduled tasks, JMS connections, etc. If you forget to add <load-on-startup> to your web.xml, then these tasks won't be started until the first access of the servlet.
You can configure the application context the other way around as well. E.g. in order to make the OpenEntityManagerInViewFilter work. Setup the ContextLoaderListener and then configure your DispatcherServlet with:
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
</servlet>
Just make sure that the contextConfigLocation parameter value is empty.
I want to share what I've done on my Spring-MVC application:
On the we-mvc-config.xml I added just the classes annotated with #Controller:
<context:component-scan base-package="com.shunra.vcat">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
On the applicationContext.xml files I added all the rest:
<context:component-scan base-package="com.shunra.vcat">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
I have a web application that loads a Spring context in the standard way:
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:META-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Unfortunately my application is not a "pure" web application, meaning that I don't have a real front end but just Akka remote actors that get initialized via a web.xml Listener as well.
My Akka actors (standard POJOs) needs to get hold of the Spring context, so my question is: how do I get hold of the Spring context from a class that has no reference to the Servlet context?
Basically I cannot use:
WebApplicationContextUtils.getWebApplicationContext(ctx);
...because Akka actors have no reference to the ServletContext.
Thanks.
You can make your own Initializer that will create an instance of a SpringContextActor with a well known id, and then the actors needing to do something with the SpringContext can look the SpringContextActor in the ActorRegistry and send messages to it.
If these POJOs are spring beans, you can make them implement ApplicationContextAware
You can use #Configurable to make any pojo a spring bean
If they are not spring beans, you can store the ServletContext in JNDI on startup, and access it via JNDI.
I'd wonder about a design that depended so strongly on the web tier.
The recommended Spring idiom is to have a POJO interface service layer that's called from the web tier. The benefit is that the service layer can be used even if the web tier is completely removed.
If you don't have a service layer, perhaps adding one would give you the flexibility to use it without the web tier or app server.
I've created a small console application to see how quartz work and it was easy to create an applicationcontext object inside the main method to get the cron run. OK now I'm in a real project managed by maven and which is using cron jobs defined in some of the modules. Each of the module has his own spring config file. I had 3 of the modules using quartz so it was setup in each of the spring config file. The web app module is the one who has the dependency of each of the modules.
Now i had few concerns:
should I created the applicationcontext as in the console project or it's supposed to be loaded. If yes, where am I supposed to load it.
based on research on the Internet I did on line I use MethodInvokingJobDetailFactoryBean for easy unit testing. And now that I have to use the CronExpression class to test the getNextValidTimeAfter, I still don't know how to organize it properly
Can anyone give me a hand. I'd really appreciate it. Thanks for reading
As per comment, the question is closer to "How to load Spring application context file(s) for a Web application".
According to Section 3.8.5, "Convenient ApplicationContext instantiation for web applications", you can register an ApplicationContext using the ContextLoaderListener as follows (add this to your web.xml file):
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- or use the ContextLoaderServlet instead of the above listener
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-->