【问题标题】:Spring: autowired DAO is null in custom UserServiceDetails implementationSpring:自动装配的 DAO 在自定义 UserServiceDetails 实现中为空
【发布时间】:2016-11-01 10:08:38
【问题描述】:

我正在我的 Spring 项目中配置安全性,不幸的是我遇到了问题。为什么 CustomUserDetailsS​​ervice.java 中自动装配的 userDAO 为空?

这里是有问题的代码:

CustomUserDetailsS​​ervice.java

@Service("customUserDetailsService")
@ComponentScan(basePackages="...")
public class CustomUserDetailsService implements UserDetailsService {

   @Autowired
   private UserDAO userDAO;

   public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

       // userDAO is null
       UserModel user = userDAO.getUserByUsername(username);
       ...
   }
}

spring-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"
   xsi:schemaLocation="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.2.xsd">

<http pattern="/resources/**" security="none"/>
<http pattern="/login" security="none"/>

<http auto-config="true">
    <intercept-url pattern="/**" access="ROLE_USER" />
    <form-login
        login-page="/login"
        default-target-url="/home"
        authentication-failure-url="/login?error"
        username-parameter="username"
        password-parameter="password" />
    <logout logout-success-url="/login?logout" />
</http>

<authentication-manager>
    <authentication-provider user-service-ref="customUserDetailsService">
        <password-encoder ref="encoder" />
    </authentication-provider>
</authentication-manager>

<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
    <beans:constructor-arg name="strength" value="10" />
</beans:bean>

<beans:bean id="customUserDetailsService" class="... .service.CustomUserDetailsService" />

编辑:

UserDAOImpl.java

public class UserDAOImpl implements UserDAO {

private JdbcTemplate jdbcTemplate;

public UserDAOImpl(DataSource dataSource) {
    jdbcTemplate = new JdbcTemplate(dataSource);
}

   public UserModel getUserByUsername(String username) {

       String sql = "SELECT * FROM users WHERE username = '" + username + "'";

       return jdbcTemplate.query(sql, new ResultSetExtractor<UserModel>() {

            public UserModel extractData(ResultSet rs) throws SQLException, DataAccessException {
               if (rs.next()) {
                   UserModel user = new UserModel();
                   user.setUsername(rs.getString("username"));
                   user.setPassword(rs.getString("passwort"));
                   user.setEnabled(rs.getBoolean("enabled"));

                   return user;
               }
               return null;
           }
       });
   }
}

下面是基于Java的配置文件中的sn-p代码:

@Bean
public UserDAO getUserDAO() {
    return new UserDAOImpl(getDataSource());
}

不过,有趣的是,这种配置似乎有点工作。当我将 UserDAO 自动连接到我的控制器时,它工作得非常好:

MainController.java

@RequestMapping(value = {"", "/", "/home"})
public String homeHandler(Model model) {

    // userDAO is not null, works perfectly fine and returns the UserModel-Object as expected
    UserModel user = userDAO.getUserByUsername("dx");

    ...
}

我已经阅读了一些问答,但到目前为止,它涉及自定义 UserDetailsS​​ervice 的手动实例化。我的代码有什么问题?

【问题讨论】:

  • 是否正在扫描?
  • java配置?是的。当我 testwise 将 DAO 自动连接到我的主控制器(与所有其他 DAO 相同)时,它不为空并且工作正常(按预期返回用户)。它在 CustomUserDetailsS​​ervice.java 中仅为空。
  • 方法getUserDAO()在哪里存在?
  • 是java配置文件。是的,我的项目同时配置了xml和java。
  • CustomUserDetailsService 处执行@ComponentScan 可能会清除Spring Bean Pool 中先前扫描的项目。但是您仍然可以从控制器访问UserDAO,因为它在通过Configuration 创建时已经被注入。无论如何,我不确定这一点。您不应该在常规组件上执行@ComponentScan。要么将其放入您的 Java 配置中,要么将其作为 &lt;context:component-scan&gt; 添加到 xml。

标签: spring spring-security autowired


【解决方案1】:

问题似乎是因为您在两个不同的地方实例化 customUserDetailsService。您在 spring-security.xml 文件中有 &lt;bean&gt; 定义,并且在类本身上有 @Service 注释。在您的 XML bean 定义中,您没有注入 UserDAO 以使其为空。

您需要简化您的项目以清理 java 配置或 XML 文件中的 bean 定义(这不是必需的,您可以拥有 XML + java 配置,但它会让人很困惑什么是实例化哪个 bean)。你的选择很少;

  1. 删除CustomUserDetailsService 的 XML 声明。在您的 XML 中添加 &lt;context:component-scan&gt; 并添加包名称,并从 CustomUserDetailsService 中删除 @ComponentScan。这将允许 spring 扫描包并注册标有@Service@Bean 等注释的 bean。确保您的 java 配置类标有 @Configuration 注释。

  2. 您可以决定对所有 bean 使用 XML 配置,在这种情况下,您需要删除 @Bean@Service 等注释并在 Spring XML bean 定义中声明所有这些并确保每个其中有适当的依赖注入。

您肯定需要清理您的 bean 定义,以便注入正确的依赖项。

【讨论】:

    【解决方案2】:

    感谢您的回复。 Setu 的回答是最有帮助的。显然,问题确实是双重实例化。我添加了&lt;context:component-scan base-package="... .service" /&gt; 并在CustomUserDetailsService 中留下了@Service("customUserDetailsService")@ComponentScan(basePackages="...") 两个注释(没有@ComponentScan 它不起作用)。

    【讨论】:

      猜你喜欢
      • 2017-08-06
      • 2018-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-19
      • 2014-01-20
      • 2015-12-01
      • 2012-04-30
      相关资源
      最近更新 更多