Singleton resources shared by several MVC controllers in Java - 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.)

Related

Understanding Spring MVC application contexts

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.

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 using different contexts and SpringBeanAutowiringSupport in jsp

I have the following problem. My multi module spring application is loading up two different contexts at startup.
Context one is loaded up with this code snippet.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
and the other one via the rest webservice
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/components_webservice.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Now I got a jsp using this command to use autowired beans inside the jsp.
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
This only makes it possible to autowire the beans defined in the main context. I can't autowire beans from the REST Servlet declared context. Is there a way to make this context available inside the jsp? I know one way would be to declare all the beans inside the main context, but I want them to keep separated.
Greetings,
smoothny
Dont put any logic inside your jsp. Autowire fields in your controllers and pass generated values to the model.

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.

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