spring工厂方法“jdbctemplate”引发异常;属性“datasource”是必需的

bq3bfh9z  于 2021-07-23  发布在  Java
关注(0)|答案(1)|浏览(318)

我正在尝试使用spring4和datasource配置连接到数据库。我遵循一个教程,所以这是正确的配置:

package spittr.config;

import ...

@Configuration
public class DataConfig {

    @Bean
    public JndiObjectFactoryBean dataSource() {
        JndiObjectFactoryBean jndiObjectFB = new JndiObjectFactoryBean();
        jndiObjectFB.setJndiName("java:jboss/datasources/jdbc/SpitterDS");
        jndiObjectFB.setProxyInterface(javax.sql.DataSource.class);
        return jndiObjectFB;
    }

    @Bean
    public JdbcOperations jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

一切正常,但正如您所见,我返回的是jndiobjectfactorybean而不是datasource。如果我很好地理解spring(可能我不理解,否则我在这里会理解),如果您不指定bean名称,spring将把bean的名称设置为返回类型,第一个字母为小写。例如,下面的代码行将返回一个id为“myfantasticbean”的bean(小写为“m”)

@Bean
public MyFantasticBean createMyBean() {
    return new MyFantasticBean();
}

我看到很多人在网上使用这个版本的dataconfig,其中方法datasource()返回一个datasource类型的对象(应该是这样的):

package spittr.config;

import ...

@Configuration
public class DataConfig {

    @Bean
    public DataSource dataSource() {
        JndiObjectFactoryBean jndiObjectFB = new JndiObjectFactoryBean();
        jndiObjectFB.setJndiName("java:jboss/datasources/jdbc/SpitterDS");
        jndiObjectFB.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource) jndiObjectFB.getObject();
    }

    @Bean
    public JdbcOperations jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

但如果使用此数据源创建,则会出现以下错误:

bin/content/10_SpringWeb_BE_JDBC.war/WEB-INF/classes/spittr/data/JdbcSpitterRepository.class"]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcTemplate' defined in class path resource [spittr/config/DataConfig.class]: Bean instantia
tion via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.jdbc.core.JdbcOperations]: Factory method 'jdbcTemplate' threw exception; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required

我甚至找到了解决方案,修改了datasource()方法,现在变成这样:

package spittr.config;

import ...

@Configuration
public class DataConfig {

    @Bean
    public DataSource dataSource(){
        final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        DataSource dataSource = dsLookup.getDataSource("java:jboss/datasources/jdbc/SpitterDS");
        return dataSource;
    }

    @Bean
    public JdbcOperations jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

但我真的不明白为什么这个有效而前一个无效。有人能解释一下我做错了什么吗?
非常感谢

iyfamqjs

iyfamqjs1#

Spring按类型连接所有豆子。这意味着它将查找返回类型为的bean定义 DataSource ,当使用java配置时。这就是使用jndidatasourcelookup时的情况,这样spring就可以毫无问题地找到它。它不能从jndiobjectfactorybean派生数据源,除非在返回时强制转换它。

@Bean
public DataSource dataSource() {
   JndiObjectFactoryBean jndiObjectFB = new JndiObjectFactoryBean();     
   jndiObjectFB.setJndiName("java:jboss/datasources/jdbc/SpitterDS");
   jndiObjectFB.setProxyInterface(javax.sql.DataSource.class);
   return (DataSource) jndiObjectFB.getObject();
}

另外,你在陈述的时候也有点搞错了
如果我很好地理解spring(可能我不理解,否则我在这里会理解),如果您不指定bean名称,spring将把bean的名称设置为返回类型,第一个字母为小写。例如,下面的代码行将返回一个id为“myfantasticbean”的bean(小写为“m”)
只有在使用组件扫描时才是这样。
因此,如果您有一个用@service等注解的类:

@Service
public class MyFantasticBean { .. }

那么是的,这个名字将是myfantasticbean,因为这个名字不能从其他东西派生。重要的是要意识到,在使用java配置时,名称不会与类型相同。

@Bean
public MyFantasticBean createMyBean() {
    return new MyFantasticBean();
}

在您的示例中,myfantasticbean是spring在您想要注入它时将搜索的bean类型。以及 createMyBean 将是bean的名称。因此,如果您有多个myfantasticbean类型的bean示例,那么您可以使用bean名称来指定要注入的bean。对你来说那就是

@Qualifier("createMyBean")
@Autowired
private MyFantasticBean myFantasticBean;

相关问题