Understanding Spring MVC application contexts - java

I am trying to understand basic Spring MVC stuff.
Consider the web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.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>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Also consider below diagram that is given in the official docs:
Doubts:
What is precise types of instances created by DispatcherServlet and ContextLoaderListener? The confusion arise, since some articles online say ContextLoaderListener creates ApplicationContext instance and DispatcherServlet creates WebApplicationContext instance. But, after looking at their source, I feel both create instance of type WebApplicationContext, and since its subtype of ApplicationContext, some articles say ContextLoaderListener creates ApplicationContext instance. Is it also the case that only ApplicationContext-provided functionalities of instance created by ContextLoaderListener are used, and hence the article say ContextLoaderListener creates ApplicationContext, but not WebApplicationContext
`
Is it like the WebApplicaionContext created by ContextLoaderListener is what usually online articles refer to as "root" WebApplicationContext, just to differentiate it from WebApplicationContexts created by DispatcherServlet?
Reading this article, I understood that DispatcherServlet loads from [servlet-name]-servlet.xml file which should load "web tier components". On the other hand ContextLoaderListener loads "middle tier components". Given that there can be only one ContextLoaderListener in web.xml (right?), there should be only single single set of "middle tier components", whereas, since there can be multiple DispatcherServlets, there can be multiple sets of "web tier components". Is this right? If so, then why the above diagram shows multiple WebApplicationContexts of middle tier components and single WebApplicationContext of web tier component?

Both WebApplicationContext and ApplicationContext are interfaces, so when documentation says "creates ApplicationContext instance" it means that it creates an object instance of a class that implements ApplicationContext. Whether that class also implements WebApplicationContext is besides the point. It may. It may not. Doesn't invalidate the statement that it "creates ApplicationContext instance".
what usually online articles refer to as "root"
No, it's what the javadoc of ContextLoaderListener itself refers to a root:
Performs the actual initialization work for the root application context.
why the above diagram shows multiple WebApplicationContexts of middle tier components and single WebApplicationContext of web tier component?
It only shows a single WebApplicationContext of web tier component because the diagram is for a single DispatcherServlet.
Just because ContextLoaderListener only creates a single root context, doesn't mean that multiple contexts couldn't be created by other means. The diagram accurately shows what is possible.

Related

How Spring Ioc container interacts with Tomcat container

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.

Spring MVC: Using #Autowire is getting references to different spring bean instances

I have a UserCredetnialsDatSourceAdapter defined in my Spring app context file. I also have a custom filter added to the Spring via the DelegatingFilterProxy.
This filter is using the #Autowire to get a reference to the DataSource Bean. I also #Autowire the DataSource in my DAO. When I debug I see different instance id's to the datasource in the Filter and DAO instances. Why are there 2 instances whenthese are singletons by default?
I also fired up jvisualvm and I looked at the heap and all my beans in my app context have 2 instances? Thanks for any insight maybe the bean pre/post processing has something do with it or maybe I should not be using #Autowire in a Filter. Any help is apprciated. Thanks!
EDIT
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-context.xml,/WEB-INF/config-context.xml</param-value>
</init-param>
Interesting I think I see what it going on. There are 2 instances because there are 2 contexts. One for the app and 1 for each request (Thread) I assume? Is there a way to specfiy which context to use? Maybe filter is not the answer and I will need to use AOP. Need to research how to inject a bean in #Aspect, if that is even possible.
Thanks!!
-Joe
You are importing your /WEB-INF/config-context.xml as part of your Root Application Context(one loaded up by ContextLoaderListener) as well as your Web Context(loaded by DispatcherServlet). You can probably remove it from the one for DispatcherServlet.

Spring Security + MVC : Questions around context definition & bean scope

I'm trying to understand the reccommended way for defining Spring Security in Spring-MVC applications, where the bean definitions is split across multiple parent/child contexts.
For example, my current app's web.xml looks as follows, (which I understand to be fairly standard)
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
/WEB-INF/securityContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
So, I have a standard ContextLoaderListener defined at /, which loads my global configs - applicationContext.xml and securityContext.xml.
I also define the spring mvc DispatcherServlet at /app/, which loads it's own beans from spring-mvc-servlet.xml.
As I understand it, config defined in spring-mvc-servlet.xml is not visible to config defined in either of the top-level context files.
Where then is the best place to define app-level security concepts? For example, I'd like to add the following filter.
<security:http pattern="/oauth/token" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint">
<security:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
</security:http>
This is so that requests to /app/oauth/token pass through this filter, and get basic authentication processed.
Because this pertains directly to a concern of the Spring-MVC app, I initially defined it in spring-mvc-context.xml (which is why the app is excluded from the url).
However, this means it's not visible to the security config defined in securityContext.xml, so it's ignored.
So, I move it up to securityContext.xml, but in doing so, also must move all the dependencies.
I quickly end up moving everything up to applicationContext.xml, which leaves the spring-mvc-context.xml almost empty.
Is this common? What is the reccomended split between what is defined in top-level contexts, and what gets defined in child contexts?
Given that spring-mvc defines a series of controllers, which I want to mark as #Secured, how will these be processed if the controller is not visible to the security context?
Do I need to move my <mvc:annotation-driven /> from the servlet.xml to the global applicationContext.xml?
Do I need additional configuration within the spring-mvc-servlet.xml to tell it to participate in Spring security?
I've read the documentation on Spring-MVC, but there's very few specifics on how to configure this.
Additionally, the Spring OAuth examples seem to define everything within a single config file, which doesn't seem very real-world, and seems to contradict other examples I've read.
First: the beans defined within applicationContext.xml (ContextLoaderListener) can not access the one defined in spring-mvc-servlet.xml (DispatcherServlet) but not the other way around.
You asked:
Given that spring-mvc defines a series of controllers, which I want to mark as #Secured, how will these be processed if the controller is not visible to the security context?
So this works without problems, because the controllers must be defined in the spring-mvc-servlet.xml, so they "see" the Spring Security stuff defined in applicationContext.xml
Do I need to move my from the servlet.xml to the global applicationContext.xml?
No
Do I need additional configuration within the spring-mvc-servlet.xml to tell it to participate in Spring security?
No
... which leaves the spring-mvc-context.xml almost empty. Is this common?
The spring-mvc-context.xml should contain every thing that is related to Web Stuff (except secrutiy). So the common parts of the spring-mvc-context.xml are component scan for #Controller, some Interceptors (mvc:interceptors), mvc:resources, mvc:default-servlet-handler, mvc:view-controller, ReloadableResourceBundleMessageSource, CookieLocaleResolver, .SimpleMappingExceptionResolver...
BTW: If you use component scan, then you need two of them, one at applicationContext.xml to scan for #Service #Repository and #Component (But not #Controller) and a second in spring-mvc-context.xml that only scan for #Controller!
#See also this question: ContextLoaderListener or not? It discuss the theme from an other point of view.

ContextLoaderListener or not?

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>

Singleton resources shared by several MVC controllers in Java

Is there a way to have a singleton resource used by multiple controllers?
We got 2 servlets, each one with its own application contexts: one-servlet.xml & two-servlet.xml and lib-context.xml with singleton bean "util".
Now, if we import lib-context.xml into each of 2 servlet contexts above, spring will create a separate application context for each servlet and we'll end up with 2 singletone objects.
Is there a way to configure application that only one singleton object will be created?
Yes. In your web.xml, load lib-context.xml with the ContextLoaderListener instead of loading it with the DispatcherServlet.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/lib-context.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
You can remove the imports from your servlet-specific app context configuration files.
All the DispatcherServlets will see not only the shared lib-context.xml above but also any contexts that they themselves load.
(You may need to adjust the param-value example I gave. That path is just an example.)

Categories