参数异常:扩展JdbcUserDetailsManager时需要'dataSource'或'jdbcTemplate'。

11

我对Spring还比较陌生,目前在尝试扩展JdbcUserDetailsManager时遇到了异常问题,因为我需要除提供的功能外的其他功能。该类的签名如下,并带有默认构造函数。

@Repository
public class PrimeUserDetailsManager extends JdbcUserDetailsManager implements CustomUserDetailsManager {

    public static String CUSTOM_USERS_BY_USERNAME_QUERY = "select username,password,enabled from users where username like ?%";  
    public static String FIND_ALL_USERS_QUERY = "select username,password,enabled from users";

    @Override
    public List<UserDetails> loadUsersByUsername(String username) {
        return super.loadUsersByUsername(username);
    }

    @Override
    public List<UserDetails> findAllUsers() {
        return getJdbcTemplate().query(FIND_ALL_USERS_QUERY, new RowMapper<UserDetails>() {
            public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
                String username = rs.getString(1);
                String password = rs.getString(2);
                boolean enabled = rs.getBoolean(3);
                return new User(username, password, enabled, true, true, true, AuthorityUtils.NO_AUTHORITIES);
            }
        });
    }
}

我自定义的接口长这样:

public interface CustomUserDetailsManager extends UserDetailsManager {
    public List<UserDetails> loadUsersByUsername(String username);
    public List<UserDetails> findAllUsers();
}

简单的自动装配:

@Service("userService")
public class UserServiceImpl implements UserService{

    @Autowired
    public UserServiceImpl(CustomUserDetailsManager customUserDetailsManager) {
        this.customUserDetailsManager = customUserDetailsManager;
    }

    private CustomUserDetailsManager customUserDetailsManager;
    ....
}

在我的ApplicationContext中,我有这个:

<beans:bean id="jdbcUserService" class="org.primefaces.examples.moviecollector.custom.PrimeUserDetailsManager">
    <beans:property name="dataSource" ref="dataSource"/>
    <beans:property name="authenticationManager" ref="authenticationManager"/>
    <beans:property name="enableGroups" value="true"/>
    <beans:property name="enableAuthorities" value="false"/>
</beans:bean>

然而,在启动我的应用程序时,我得到了下面的异常,所以显然我肯定错过了什么?有人能告诉我是什么吗?

完整的堆栈跟踪:

2011-sep-07 13:08:49 org.apache.catalina.core.StandardContext listenerStart
ALLVARLIG: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userBean' defined in file [C:\Program\springsource\vfabric-tc-server-developer-2.5.0.RELEASE\Localhost\wtpwebapps\prime-sweet\WEB-INF\classes\org\primefaces\examples\moviecollector\beans\UserBean.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.security.provisioning.GroupManager]: : Error creating bean with name 'primeUserDetailsManager' defined in file [C:\Program\springsource\vfabric-tc-server-developer-2.5.0.RELEASE\Localhost\wtpwebapps\prime-sweet\WEB-INF\classes\org\primefaces\examples\moviecollector\custom\PrimeUserDetailsManager.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primeUserDetailsManager' defined in file [C:\Program\springsource\vfabric-tc-server-developer-2.5.0.RELEASE\Localhost\wtpwebapps\prime-sweet\WEB-INF\classes\org\primefaces\examples\moviecollector\custom\PrimeUserDetailsManager.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:730)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1003)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:907)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:276)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:197)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4701)
    at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5204)
    at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5199)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
    at java.lang.Thread.run(Thread.java:619)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primeUserDetailsManager' defined in file [C:\Program\springsource\vfabric-tc-server-developer-2.5.0.RELEASE\Localhost\wtpwebapps\prime-sweet\WEB-INF\classes\org\primefaces\examples\moviecollector\custom\PrimeUserDetailsManager.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:844)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:786)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:795)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:723)
    ... 23 more
Caused by: java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
    at org.springframework.jdbc.core.support.JdbcDaoSupport.checkDaoConfig(JdbcDaoSupport.java:112)
    at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
    ... 34 more

编辑: 我在上面包含了整个PrimeUserDetailsManager的主体内容。这是dataSource的定义:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
    <property name="driverClassName" value="${database.driver}"/>
    <property name="url" value="${database.url}"/>
    <property name="username" value="${database.username}"/>
    <property name="password" value="${database.password}"/>
</bean>

@Bozho:我以为dataSource是从JdbcUserDetailsManager继承而来的,但看起来我错了...所以我猜我只需要将它添加到PrimeUserDetailsManager中? - Daniel
@mgamulin:整个CustomerUserDetailsManager在我的第一篇帖子中都有提供。 - Daniel
抱歉:<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name="driverClassName" value="${database.driver}"/> <property name="url" value="${database.url}"/> <property name="username" value="${database.username}"/> <property name="password" value="${database.password}"/> </bean> - Daniel
抱歉,我没有更新我的第一篇帖子的权限 :-/ - Daniel
创建名为'primeUserDetailsManager'的bean时出错。你能发布Spring中这个bean的定义吗? - nicholas.hauschild
显示剩余4条评论
4个回答

10
您有两个bean。其中一个在XML中定义。另一个被创建是因为您已经使用了@Repository注释来注释您的类。这是导致问题的那个,因为您没有给它关于连接所需的“'dataSource'或 'jdbcTemplate'”指令。请注意,在异常中,bean的名称是“primeUserDetailsManager”。这是小写的简单类名,这是通过使用注释进行组件扫描创建的默认bean名称。

啊,我对Spring的了解不足。看来我得再翻一下参考手册 :-) 干杯! - Daniel

7

我创建了一个中间类JdbcDaoSupport,它是所有DAO类继承的超类,看起来像这样:

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class MyJdbcDaoSupport extends JdbcDaoSupport {
    @Autowired private DataSource dataSource;
    @PostConstruct
    private void initialize() {
        setDataSource(dataSource);
    }
}

假设您有一个数据源bean,其ID为“dataSource”,如OP所示。
对于我来说,在Spring 4.x中有效,但早期版本也应该可以使用。

2
这个解决方案同样适用于Spring 5.0.8。MyDao类继承了JdbcDatoSupport并实现了一个接口。 - Andrea Girardi

1

我解决这个问题的唯一方法是在我的DAO中定义以下内容。

 private SimpleJdbcTemplate simpleJdbcTemplate;

    protected SimpleJdbcTemplate getSimpleJdbcTemplate() {
        return simpleJdbcTemplate;
    }

    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    }

看起来SimpleJdbcDaoSupport没有在其setDataSource方法上使用@Autowired注释。


1

这在Spring 2.5中也可以工作。

/**
 * Sets the parent class DataSource to the auto-wired data source.
 * 
 * 
 */
@Autowired
public void setParentDataSource(
        @Qualifier("dataSource") DataSource dataSource) {
    super.setDataSource(dataSource);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接