我使用autowire @Controller创建了一个名为RegistrationController的弹簧控制器。为了我自己的好奇心,我创建了一个默认构造函数,如下所示,并添加了一个logger语句:
public RegistrationController() {
logger.info("Registration Controller (Constructor) called-->"+this);
}
我发现当我在日志文件中的spring source IDE(v2.9)中启动我的tomcat服务器(v7)时,我看到以下内容:
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
据我所知,RegistrationController默认情况下应该是singleton对象,并且只能创建一个实例。但是,正如您可以从日志文件中看到的那样,创建了两个实例。不知怎的,我觉得这不正确。但我没有确切的答案。
我的web.xml中的一些重要行如下:
<?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>
正如您必须猜到的,我有一个main-servlet.xml和applicationContext.xml作为我的spring配置文件。
你能帮我理解这里发生了什么吗?
由于我无法回答8个HRS之前我的问题:
感谢@Andna建议在applicationContext.xml和main-servlet.xml中查找<context:component-scan />
。我在文件中都有这个元素,因此每个春豆都被扫描了两次。
但是,从applicationContext.xml中删除<context:component-scan />
会导致我的Spring安全配置中断。为了更详细,我创建了一个实现org.springframework.security.core.userdetails.UserDetailsService
@Service("userDetailsService")
public class DuncanUserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
}
}
为了支持这个类,我在applicationContext-security.xml(缩短版本)文件中有以下内容:
<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>
因此,从applicationContext.xml中删除<context: component-scan />
导致“userDetailsService”对象实例丢失,我的日志文件中出现了大量错误。
所以我做的是将组件扫描保存在main-servlet.xml中:
<context:component-scan base-package="com.some.org" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
但是,我使用applicationContext.xml中的exclude过滤器编辑了组件扫描,如下所示:
<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>
这有助于我实现这两件事:
感谢大家提出的所有好建议。
答案 0 :(得分:4)
也许你在applicationContext.xml
和main-servlet.xml
都进行了两次组件扫描,因此Spring会对两次带注释的类进行扫描?
答案 1 :(得分:1)
我最终在 src / main / webapp / WEB-INF / web.xml中进行了以下配置:
<web-app xmlns=... version="2.4">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml,/WEB-INF/security.xml,/WEB-INF/db.xml,/WEB-INF/services.xml</param-value>
</context-param>
<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>
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
我认为Spring最常见的问题是对Spring语境的误解。仔细看看DispatcherServlet。 Spring将自动搜索 web context 的dispatcher-servlet.xml。来自此上下文的Bean不适用于根上下文中定义的bean,例如在 contextConfigLocation 参数中指定。为了使它可用,人们通常在contextConfigLocation中包含dispatcher-servlet.xml,这在逻辑上导致Spring初始化Web上下文两次。然后配置spring-security(全局方法安全性)或组件扫描或sitemesh将是一场噩梦,并且配置将是“不稳定的”#34;