java - 正在创建 Spring 多个 bean 实例

标签 java spring

我使用 Autowiring @Controller 创建了一个名为 RegistrationController 的 Spring Controller 。为了我自己的好奇心,我创建了一个默认构造函数,如下所示并添加了一个记录器语句:

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

我发现当我在日志文件中的 spring 源代码 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 默认情况下应该是单例对象,并且只需要创建一个实例。但是,正如您从日志文件中看到的那样,创建了两个实例。不知何故,我觉得这是不正确的。但我没有确切的答案。

我的 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 小时之前回答我的问题而被编辑:

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

但是,删除 <context:component-scan />来自 applicationContext.xml 导致我的 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>

因此删除 <context: component-scan />来自 applicationContext.xml 导致“userDetailsS​​ervice”对象实例丢失,我的日志文件中出现大量错误。

所以我所做的就是将组件扫描保留在 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 中的排除过滤器编辑了组件扫描,如下所示:

<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. 确保单例对象确实是单例
  2. 确保 Spring 安全性像以前一样工作。

感谢大家提出的所有精彩建议。

最佳答案

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

关于java - 正在创建 Spring 多个 bean 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11975922/

相关文章:

java - Thymeleaf 不热插拔 Intellij

java - Android 调用 AsyncTask 时崩溃

java - java打印数组越界

java - 为什么事件循环使用多个线程?

java - Log4j 日志在没有 log4j.properties 的情况下显示在控制台上

java - 查看 Spring MVC 中的逻辑

java - 是否可以使用 java 删除 gemfire 中的特定数据(键及其特定值)?

java - 使用 spring 的 SimpleJdbcCall 执行存储函数不给出输出

java - 尝试通过 linkText 与 Webdriver 查找链接时,有没有办法忽略大写字母?

java - 通过 Fragment 父类(super class)或扩展 Fragment 类引用 fragment 有什么区别?