2012-08-15 123 views
3

我使用autowire @Controller创建了一个名为RegistrationController的弹簧控制器。我有我自己的好奇心的缘故创建一个默认的构造函数如下,并增加了记录声明:正在创建Spring多个bean实例

public RegistrationController() { 
    logger.info("Registration Controller (Constructor) called-->"+this); 
} 

我发现,当我在春源IDE(V2.9)在开始我的Tomcat服务器(第7版)日志文件我看到以下内容:

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-->[email protected] 
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-->[email protected] 

据我所知,在默认情况下这个RegistrationController应该是单独的对象,必须进行创建只有一个实例。但是,正如您从日志文件中看到的那样创建了两个实例。不知何故,我觉得这是不正确的。但我没有确切的答案。

一些从我的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> 

您一定已经猜到了,我有一个主servlet.xml中和的applicationContext.xml作为我的Spring配置文件。

你能帮我理解这里发生了什么吗?

EDITED因为我不能回答我的问题之前8个小时已经过去了:

感谢@Andna您的建议,以寻找在applicationContext.xml中和主servlet.xml中<context:component-scan />。我在这两个文件中都有这个元素,因此每个春天的bean都被扫描了两次。

但是,从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 />导致“userDetailsS​​ervice”对象实例丢失,并且我的日志文件中出现大量错误。

所以我所做的就是我一直在我的组件扫描在主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排除筛选如下编辑组件扫描:

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

这帮助我实现这两个事情:

  1. 在确认单objec t确实是单身人士
  2. 确保Spring安全性与以前一样工作。

谢谢大家的所有精彩建议。

+6

applicationContext.xml和main-servlet.xml的内容? – bluesman 2012-08-15 19:40:23

+0

我认为8小时已经过去了很长时间,您可以编辑问题的答案并将其添加为真正的答案。 – 2014-02-07 13:52:10

回答

4

也许你在applicationContext.xmlmain-servlet.xml中都有组件扫描两次,所以Spring会扫描注释类两次?

+0

是的安娜,你是绝对正确的!但是,如果我从applicationContext.xml中删除,那么我对Spring安全配置有问题。 – Raj 2012-08-15 19:54:03

+0

将您的spring安全配置导入到applicationContext.xml中,并删除main-servlet.xml中的一个。 – rptmat57 2012-08-15 20:09:33

+0

@ rptmat57请看我的回答。 – Raj 2012-08-15 20:14:53

1

我结束了下面的配置,的src /主/ web应用/ 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上下文的误解。仔细看看DispatcherServlet。 Spring将自动搜索dispatcher-servlet.xml,它是Web上下文。来自此背景的豆类不可用于在根环境中定义的豆类,例如,在contextConfigLocation参数中指定。为了使其可用,人们通常在contextConfigLocation中包含dispatcher-servlet.xml,这在逻辑上会导致Spring初始化Web上下文两次。那么配置spring-security(全局方法安全)或组件扫描或sitemesh将会是一场噩梦,配置将会“不稳定”。