【问题标题】:@Autowired fails for JdbcTemplate when DAO has @Repository当 DAO 具有 @Repository 时,JdbcTemplate 的 @Autowired 失败
【发布时间】:2017-05-20 05:00:51
【问题描述】:

这似乎是一个明显的错误,但我无法找到它。以下是我的代码和配置:

应用类

@SpringBootApplication
public class Application {
    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

SQL 配置类

@Configuration
public class PostgreSQLConfig {
    @Bean
    public DataSource getDBDataSource() {
        final DriverManagerDataSource driverManagerDataSource
                = new DriverManagerDataSource(
                        "jdbc:postgresql://localhost:5432/applicationdb",
                        "username",
                        "password"
                );

        driverManagerDataSource.setDriverClassName("org.postgresql.Driver");
        return driverManagerDataSource;
    }


    @Bean
    public JdbcTemplate getJdbcTemplate(final DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

@Repository DAO 类

@Repository
public class CustomDAO {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    .
    .

@Component DAO 类

@Component
public class AnotherDAO {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    .
    .

JdbcTemplate 对象为 @Component 注释类填充。但是 @Repository 带注释的类的对象为空。我在将日志记录设置为 DEBUG 的情况下启动了 Spring Boot,但在创建 JdbcTemplate bean 时找不到任何错误。从日志中,我可以推断出方法被调用并创建了 bean。 JdbcTemplate 也引用了DataSource

如果将@Repository 注释更改为@Component,则代码可以正常工作。

  1. 在使用spring jdbc时,我们可以用注解一个DAO类吗? @Repository?
  2. 为什么依赖注入与@Component 一起工作但失败了 @Repository?

根据 M. Deinum 的建议,我做了以下更改。

  • 删除了PostgreSQLConfig
  • 添加了application.properties文件

application.properties

spring.datasource.url=jdbc:postgresql://localhost:5432/applicationdb
spring.datasource.user=username
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver

属性由 spring 应用程序加载。以下是日志消息:

2017-01-06 15:03:02 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.driver-class-name' in [applicationConfigurationProperties] with type [String]
2017-01-06 15:03:02 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.password' in [applicationConfigurationProperties] with type [String]
2017-01-06 15:03:02 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.user' in [applicationConfigurationProperties] with type [String]
2017-01-06 15:03:02 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.url' in [applicationConfigurationProperties] with type [String]

我收到一个异常。详情如下:

2017-01-06 15:03:05 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.jdbc.core.JdbcTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1474)

DAO 类标有@Repository 注解。

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.4.3.RELEASE'
    }
}


apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'idea'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'


def applicationVersion = '0.0.1-SNAPSHOT'

def dependencyVersions = [
    slf4j: '1.7.22',
    logback: '1.1.8',
    postgresql: '9.4.1212',
    junit: '4.12'
]


group = 'com.appl'
version = applicationVersion
mainClassName = 'com.appl.Application'


war {
    baseName = 'my-custom-appl'
    version = applicationVersion
}

war.dependsOn test


repositories {
    mavenCentral()
}


sourceCompatibility = 1.8
targetCompatibility = 1.8


configurations.all {
    exclude group: 'commons-logging', module: 'commons-logging'
}


dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web'
    compile 'org.springframework.boot:spring-boot-starter-jdbc'
    compile 'org.springframework:spring-jdbc'
    compile "org.slf4j:jcl-over-slf4j:${dependencyVersions.slf4j}"
    compile "org.postgresql:postgresql:${dependencyVersions.postgresql}"
    compile "ch.qos.logback:logback-classic:${dependencyVersions.logback}"
    testCompile "junit:junit:${dependencyVersions.junit}"
    testCompile 'org.springframework.boot:spring-boot-starter-test'
}

【问题讨论】:

  • 只是为了确认您是否检查了您的进口声明!
  • 所有注释都正确导入。对于 JdbcTemplate,我自己验证了两次。
  • 我忘了在问题中提到,我使用的是 Spring 4.3.5.RELEASE。我正在开发 POC 产品。
  • 删除你的PostgreSQLConfig,只为application.properties添加一些属性,Spring Boot已经配置了一个数据源,JdbcTemplate不需要自己做。 dao/repo 应使用 @Repository 注释。
  • 你有 spring-boot-starter-jdbc 作为依赖吗?

标签: spring spring-boot spring-jdbc


【解决方案1】:

我找到了问题的(正在发生的部分)解决方案。 DAO 类中的方法标记为final,而@Repository 不适用于final 方法。从日志中,我可以推断出@Repository 尝试为 DAO 类创建代理,但失败了。

@Repository 替换为@Component 时,代码运行良好。再次从日志中,我可以看到 @Component 没有创建代理,并且该方法的 final 状态被忽略。

以下是Spring的调试日志:

当方法是final并且DAO Class被标记为@Repository

2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'customDAO' via constructor to bean named 'getJdbcTemplate'
2017-01-08 09:19:03 [main] DEBUG c.j.l.d.CustomDAO - Received JdbcTemplate: org.springframework.jdbc.core.JdbcTemplate@3dedb4a6
2017-01-08 09:19:03 [main] INFO  c.j.l.d.CustomDAO - Constructor Called
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'customDAO' to allow for resolving potential circular references
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Creating CGLIB proxy: target source is SingletonTargetSource for target object [com.j.l.data.CustomDAO@19542407]
2017-01-08 09:19:03 [main] INFO  o.s.aop.framework.CglibAopProxy - Unable to proxy method [public final int com.j.l.data.CustomDAO.persistEvent(java.util.List)] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'equals' method: public boolean java.lang.Object.equals(java.lang.Object)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public java.lang.String java.lang.Object.toString()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'hashCode' method: public native int java.lang.Object.hashCode()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.springframework.aop.Advisor)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.aopalliance.aop.Advice)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isFrozen()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setTargetSource(org.springframework.aop.TargetSource)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(int,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setExposeProxy(boolean)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isExposeProxy()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isProxyTargetClass()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract org.springframework.aop.TargetSource org.springframework.aop.framework.Advised.getTargetSource()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setPreFiltered(boolean)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(int,org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isPreFiltered()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.Class[] org.springframework.aop.framework.Advised.getProxiedInterfaces()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isInterfaceProxied(java.lang.Class)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract org.springframework.aop.Advisor[] org.springframework.aop.framework.Advised.getAdvisors()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.removeAdvisor(int) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvisor(org.springframework.aop.Advisor)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.replaceAdvisor(org.springframework.aop.Advisor,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvice(org.aopalliance.aop.Advice)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.String org.springframework.aop.framework.Advised.toProxyConfigString()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.Class org.springframework.aop.TargetClassAware.getTargetClass()
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'customDAO'

当方法不是final并且DAO类被标记为@Repository

2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'getJdbcTemplate'
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'anotherDAO' via constructor to bean named 'getJdbcTemplate'
2017-01-08 09:19:03 [main] DEBUG c.j.l.data.AnotherDAO - Received JdbcTemplate: org.springframework.jdbc.core.JdbcTemplate@3dedb4a6
2017-01-08 09:19:03 [main] INFO  c.j.l.data.AnotherDAO - Constructor Called
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'anotherDAO' to allow for resolving potential circular references
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Creating CGLIB proxy: target source is SingletonTargetSource for target object [com.j.l.data.AnotherDAO@907f2b7]
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public void com.j.l.data.AnotherDAO.persistEvent(com.j.l.model.EmergencyUserResponse)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'equals' method: public boolean java.lang.Object.equals(java.lang.Object)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public java.lang.String java.lang.Object.toString()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'hashCode' method: public native int java.lang.Object.hashCode()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.springframework.aop.Advisor)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.aopalliance.aop.Advice)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isFrozen()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setTargetSource(org.springframework.aop.TargetSource)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(int,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setExposeProxy(boolean)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isExposeProxy()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isProxyTargetClass()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract org.springframework.aop.TargetSource org.springframework.aop.framework.Advised.getTargetSource()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setPreFiltered(boolean)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(int,org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isPreFiltered()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.Class[] org.springframework.aop.framework.Advised.getProxiedInterfaces()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isInterfaceProxied(java.lang.Class)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract org.springframework.aop.Advisor[] org.springframework.aop.framework.Advised.getAdvisors()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.removeAdvisor(int) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvisor(org.springframework.aop.Advisor)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.replaceAdvisor(org.springframework.aop.Advisor,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvice(org.aopalliance.aop.Advice)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.String org.springframework.aop.framework.Advised.toProxyConfigString()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.Class org.springframework.aop.TargetClassAware.getTargetClass()
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'anotherDAO'

当方法是 final / not final 并且 DAO 类被标记为 @Component

2017-01-08 09:13:21 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'customDAO' via constructor to bean named 'getJdbcTemplate'
2017-01-08 09:13:21 [main] DEBUG c.j.l.d.CustomDAO - Received JdbcTemplate: org.springframework.jdbc.core.JdbcTemplate@67fe380b
2017-01-08 09:13:21 [main] INFO  c.j.l.d.CustomDAO - Constructor Called
2017-01-08 09:13:21 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'customDAO' to allow for resolving potential circular references
2017-01-08 09:13:21 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2017-01-08 09:13:21 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'customDAO'

我仍然无法理解为什么@Repository 创建代理而@Component 跳过它?有没有办法在 DAO 类上标记方法 final 并使用 @Repository

如果需要,我可以为此创建一个单独的问题。

【讨论】:

    猜你喜欢
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-31
    相关资源
    最近更新 更多