ContextLoaderListener or not? - java

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>

Related

Java Spring: Trying to configure webflow by xml, can't find dispatcher-servlet.xml

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

Spring - how to load properties prior to context loader getting called

I would like to read the properties from my properties files in my custom contextLoadListener. However my listener class gets executed prior to spring loading the properties file. How do I get my 'rdbaccess.properties' loaded prior to the execution of my CustomContextLoaderListener class? Below is my relevant parts of the configuration.
In web.xml
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
com.my.package.setup.CustomContextLoaderListener
</listener-class>
</listener>
In spring-servlet.xml
<context:component-scan base-package="com.my.package" />
<context:property-placeholder location="classpath:rdbaccess.properties" />
The ContextLoader(Listener) is the instance that initializes your Spring context. This has to be the very first thing happening in the lifecycle of your (Spring) application, at all. It's not possible that your properties get loaded before the context has initialized. You can't decorate your living room before you've built the house :)
However, regarding the name of your properties, you probably need to inject the database credentials into your beans. This issue can be resolved with another approach, which is a lot cleaner in my opinion, especially for applications that run in multiple environments.
Instead of keeping/putting the credentials in your classpath, you should configure properties that change for each environment (local, development, integration, production ...) right there. For example, if you run a Tomcat, then put a properties file into the conf directory containing your database credentials. You can access that file in your custom ContextLoaderListener and provide the properties to your beans through a class with a static properties map, for instance.
Try adding a custom context initializer to load your properties file, like so:
https://gist.github.com/rponte/3989915

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.

Why is my Spring ContextRefreshed event called twice?

I have a Spring ApplicationListener bean registered to listen for ContextRefreshed events. For some odd reason though, I get two calls to the onApplicationEvent(ContextRefreshedEvent) method at the completion of the context initialization. Is this normal behavior or is it indicative of a problem with my configuration? I'm using Jetty 8 for my Servlet container.
My relevant web.xml configuration is as follows
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/spring/spring-config.xml</param-value>
</context-param>
<servlet>
<servlet-name>Spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet-mapping>
<servlet-name>Spring</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
Thanks!
Even though you did not specify a contextConfigLocation for your DispatcherServlet it still creates a child context and the second refreshed event is for that context. Use event.getApplicationContext() to find out which context the event is for.
it happened to me as well, on a different event-listener. (ApplicationListener<AuthenticationFailureBadCredentialsEvent>)
I suspected the ContextLoaderListener, and when I removed the declaration from the web.xml, the app was working properly. Then I had to figure out what is its purpose, of the ContextLoaderListener...
Role/Purpose of ContextLoaderListener in Spring?
the interesting answer there is:
ContextLoaderListener is optional. Just to make a point here: you can
boot up a Spring application without ever configuring
ContextLoaderListener ...just the basic minimum web.xml with
DispatcherServlet
It looks like bug.
https://jira.springsource.org/browse/SPR-6589
If you are using 3.0 try it on the latest available release which is 3.05.
I had this problem too but fixed it. I was injecting the dataSource into my DAO (and instantiating a JdbcTemplate with it)....but I also had a Spring bean configured for JDBCTemplate.
I should have been injecting my DAO with the jdbcTemplate...that avoids the duplicate.

Categories