WEB-INF/myproject-servlet.xml versus WEB-INF/web.xml - java

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>

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 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>

using quartz in a web app with spring

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>
-->

Categories