I have created a spring controller called RegistrationController using autowire @Controller. I have for my own curiosity sake created a default constructor as follows and added a logger statement:
public RegistrationController() {
logger.info("Registration Controller (Constructor) called-->"+this);
}
What I found was when I start my tomcat server (v7) in spring source IDE (v2.9) in the log file I see the following:
INFO: Initializing Spring root WebApplicationContext
2012-08-15 15:12:28,808 [pool-2-thread-1] INFO com.controllers.registration.RegistrationController - Registration Controller (Constructor) called-->com.controllers.registration.RegistrationController@78c0dc2
Aug 15, 2012 3:12:28 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'main'
2012-08-15 15:12:29,256 [pool-2-thread-1] INFO com.controllers.registration.RegistrationController - Registration Controller (Constructor) called-->com.controllers.registration.RegistrationController@773ba8d6
I understand that the RegistrationController by default should be singleton object and only one instance must be created. However, as you can see from the log file that two instances are created. Somehow I feel this is not correct. But I don't have the exact answer.
Some of the important lines from my web.xml are as follows:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext*.xml</param-value>
</context-param>
.
.
<servlet>
<servlet-name>main</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
.
.
</web-app>
As you must have guessed, I have a main-servlet.xml and applicationContext.xml as my spring configuration files.
Can you please help me understand what is happening here?
EDITED SINCE I CANNOT ANSWER MY QUESTION BEFORE 8 HRS HAS ELAPSED:
Thanks to @Andna for the suggestion to look for the <context:component-scan />
in applicationContext.xml and main-servlet.xml. I had that element in both the file and hence every spring bean was scanned twice.
However, removing the <context:component-scan />
from the applicationContext.xml caused my Spring security configuration to break. To go in more detail I had created a class that implemented org.springframework.security.core.userdetails.UserDetailsService
@Service("userDetailsService")
public class DuncanUserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
}
}
To support this class I had the following in my applicationContext-security.xml (shortened version) file:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
<beans:bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref= "passwordEncoder">
<salt-source user-property="userName"/>
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
</beans:beans>
Therefore removing <context: component-scan />
from the applicationContext.xml caused the "userDetailsService" object instance to go missing and I got tonnes of errors in my log file.
So what I did was I kept my component scan in the main-servlet.xml as it is:
<context:component-scan base-package="com.some.org" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
However, I edited the component scan using the exclude filter in the applicationContext.xml as follows:
<context:component-scan base-package="com.bankofamerica" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="regex" expression="com.some.org.common.http.HTTPClient" />
</context:component-scan>
This helped me in achieving both the thing:
- Making sure that the singleton object was indeed singleton
- Making sure that the Spring security work as before.
Thank you all for all the wonderful suggestions.