Spring Data JPA - 注入失败 - BeanCreationException:无法自动装配字段 [英] Spring Data JPA - injection fails - BeanCreationException: Could not autowire field

查看:52
本文介绍了Spring Data JPA - 注入失败 - BeanCreationException:无法自动装配字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遵循了此处 以获得与 Spring Data JPA 一起使用的基础应用程序.现在,我是如何理解的,使用配置

i followed the tutorial posted here to get a basis application to work with Spring Data JPA. Now, how i understood, using the configuration

<jpa:repositories base-package="my.package.to.scan" />

应该会导致 Spring Data JPA 为扩展 JpaRepository 的接口扫描该包,并创建它的 concreate bean,以便它可以使用简单的 Spring @Autowired 在我的服务类中的任何地方使用.但它失败了,说它找不到带有 className 的 bean(这是 bean 在创建时获得的默认名称,只需使用去大写的 ClassName).

should result in that package beeing scanned by Spring Data JPA for interfaces extending JpaRepository and create a concreate bean of it so it can be used anywhere in my service classes using simple Spring @Autowired. But it fails, saying it can't find a bean with className (which is the default name the bean gets when created, simply using the de-capitalized ClassName).

但是,当我像这样在 applicationContext 中手动配置 bean 时:

However, when i configure the bean manualy in my applicationContext like this:

<bean id="ClassName" class="my.package.to.scan.ClassName"/>

Spring 能够找到 bean.然后我当然会得到一个错误,因为我想从一个接口创建一个 bean,这显然不能工作.但关键是 Spring Data JPA自动创建 bean"似乎以某种方式失败了.

Spring is able to find the bean. I then of course get an error because i want to create a bean from an interface, which obviously can't work. BUT the point is that it seems like the Spring Data JPA "automatic bean creation" seems to fail somehow.

我附上了相关的代码,你可以看看.顺便说一句,我应该提到我正在开发一个 portlet,所以不要奇怪为什么我没有 spring-config.我目前只使用 applicationConfig 和 MyPortlet-Portlet.xml 进行 portlet 配置(但这应该与此问题无关).我添加了导入语句只是为了确保我没有使用错误的注释/类.

I attached the relevant code so you can look at it. Btw, i should mention that i'm developing a portlet, so don't wonder why i dont have a spring-config. I'm currently using a applicationConfig only plus an MyPortlet-Portlet.xml for portlet configurations (but that should be not relevent for this problem). I added the import statements just to make sure i'm not using the wrong annotions / classes.

applicationContext.xml

<beans *** ALL MY XMLN's and XSI's *** />
<context:annotation-config />
<jpa:repositories base-package="model.repositories" />

// JPA specific configuration here: dataSource, persistenceUnitManager exceptionTranslator, entityManagerFactory, SessionFactory, transactionManager - should not be relevant for this problem, tell me if i'm wrong

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

ICustomerService - 只是 CustomerService 的一个接口

import model.entities.Customer;
public interface ICustomerService {
        // example method
    public Customer getCustomer(Long customerId);   
}

CustomerService - 我的应用程序逻辑用来获取/设置 ORM 数据的类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import model.entities.Customer;
import model.repositories.CustomerRepository;
import model.service.interfaces.ICustomerService;
@Repository
@Transactional(readOnly = true)
public class CustomerService implements ICustomerService{
    @Autowired
    private CustomerRepository repository;

    // example method
    @Override
    public Customer getCustomer(Long customerId){
        return repository.findById(customerId);
    }

CustomerRepository - Spring Data JPA 的存储库

import javax.annotation.Resource;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;
import model.entities.Customer;
@Resource
@Transactional(readOnly = true)
public interface CustomerRepository extends JpaRepository<Customer, Long>{

    public Customer findById(Long id);
}

客户 - 我的示例实体

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "Customers")
public class Customer{

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "ID_CUSTOMER")
    private Long    id;

    @Column(name = "dbfirstname")
    private String  firstName;

    @Column(name = "dbname")
    private String  lastName;

    public Long getId(){
        return id;
    }

    public String getFirstName(){
        return firstName;
    }

    public void setFirstName(String firstName){
        this.firstName = firstName;
    }

    public String getLastName(){
        return lastName;
    }

    public void setLastName(String lastName){
        this.lastName = lastName;
    }
}

我刚从 WebSphere 的类路径地狱中回来(该死,这是一个多么糟糕的产品),现在我来了.希望有人能帮我解决这个问题.

i just came from classpath hell with WebSphere (damn, what a fu**ed up product) and now i'm here. hope somebody can help me with this.

对究竟出了什么问题的基本解释,也许可以更好地理解弹簧自动装配注入功能会很棒.我已经阅读了 spring 文档,但说实话:有很多方法可以配置某些东西,但我不太清楚选择其中一种配置样式时真正需要的是什么.

A basic explanation of what exacly goes wrong and maybe providing a better understanding of springs autowired injection feature would be great. I've read the spring documentation, but to say the truth: there are so many ways to configure something and it's not quite visible to me WHAT is really needed when choosing one of the config styles.

编辑

尝试更新项目后,我仍然收到错误消息.按照这里的要求提供更多详细信息(跟踪):

After trying to update the project i'm still getting the error. as requested here a little more details (trace):

Exception created : org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private model.repositories.CustomerRepository model.service.CustomerService.repository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
    [...]
        at com.ibm.ws.http.HttpConnection.run(HttpConnection.java:522)
    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1563)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private model.repositories.CustomerRepository model.service.CustomerService.repository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:506)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284)
    ... 96 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:149)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1442)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:848)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:790)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
    ... 98 more
Caused by: java.lang.NullPointerException
    at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus(JtaStatusHelper.java:73)
    at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.isActive(JtaStatusHelper.java:115)
    at org.hibernate.engine.transaction.internal.jta.CMTTransaction.join(CMTTransaction.java:149)
    at org.hibernate.ejb.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1215)
    at org.hibernate.ejb.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.java:177)
    at org.hibernate.ejb.EntityManagerImpl.<init>(EntityManagerImpl.java:89)
    at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:179)
    at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:174)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:600)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:376)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:517)
    at $Proxy325.createEntityManager(Unknown Source)

    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:234)
    at $Proxy328.createNamedQuery(Unknown Source)
    at org.springframework.data.jpa.repository.query.NamedQuery.<init>(NamedQuery.java:74)
    at org.springframework.data.jpa.repository.query.NamedQuery.lookupFrom(NamedQuery.java:96)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:128)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:162)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:71)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:303)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:157)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:120)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:39)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)

编辑 #2根据要求添加了完整的 applicationContext.xml(包括我根据正在进行的讨论所做的更改)

EDIT #2 compleate applicationContext.xml (includeing the changes i made based on the ongoing discussion) added as requested

<context:annotation-config />

<jpa:repositories base-package="model.repositories" />

<context:component-scan base-package="model,model.repositories,model.service,controller" />

<bean class="model.service.CustomerService"/>
<bean class="model.service.OrderService"/>
<bean class="model.repositories.CustomerRepository"/>
<bean class="model.repositories.OrderRepository"/>


<bean id="myExceptionTranslator" class="org.springframework.orm.hibernate4.HibernateExceptionTranslator" /> 

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/mydata"
    resource-ref="true" cache="true" />


<bean id="pum"
    class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
    <property name="persistenceXmlLocations">
        <list>
            <value>classpath*:META-INF/OverridePersistence.xml</value>
        </list>
    </property>
    <property name="defaultDataSource" ref="dataSource" />
</bean>


<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="generateDdl" value="true" />
            <property name="database" value="MYSQL" />
        </bean>
    </property>
    <property name="persistenceUnitManager" ref="pum" />
    <property name="persistenceUnitName" value="default" />
</bean>

<bean id="mySessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="model"/>
    <property name="hibernateProperties">
        <value>hibernate.dialect=org.hibernate.dialect.MySQLDialect</value>
    </property>
</bean>

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="sessionFactory" ref="mySessionFactory" />
</bean>

<tx:annotation-driven />

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

推荐答案

问题很可能出在您未显示的某些配置中.如果您发布您遇到的错误,那也很好.它可能与您认为的不同.

The problem is very probably in some of the configuration you haven't shown. It would also be good if you posted the error you're getting. It might be something different than what you think it is.

关于您的配置,我注意到的一件事是您使用的是 context:annotation-config 而不是 context:component-scan.后者将根据 @Component 注释系列自动检测和创建 bean.前者不这样做.

One thing I notice about your config is that you're using context:annotation-config instead of context:component-scan. The latter will auto-detect and create beans based on the @Component family of annotations. The former doesn't do that.

除此之外,您发布的所有内容看起来都应该可以工作,尽管有一些奇怪的事情,我稍后会谈到.我将您发布的所有代码复制到示例项目中并填写了一些细节,例如 maven pompersistence.xml,以及 applicationContext.xml.我还向服务添加了一个创建"方法,因此它实际上可以做一些事情.有了这些和一个主类来驱动这一切,这是一个可运行的例子.你可以浏览github上的代码,也可以克隆并运行它:

Other than that, everything you posted looks like it should work, though there are several odd things, which I'll come to in a moment. I copied all your posted code into a sample project and filled in a few details, like a maven pom, a persistence.xml, and the missing pieces of the applicationContext.xml. I also added a "create" method to the service so it would actually do something. With those in place and a main class to drive it all, it's a runnable example. You can browse the code on github, or you can clone and run it with:

git clone git://github.com/zzantozz/testbed tmp
cd tmp/stackoverflow/10539417-basic-spring-data-jpa
mvn -q compile exec:java -Dexec.mainClass=rds.testbed.springDataJpa.SpringDataJp

现在是我注意到的奇怪之处.从顶部:

Now for the oddities that I noticed. From the top:

  • 根据给定的代码,不需要 您已添加到 applicationContext.xmlPersistenceAnnotationBeanPostProcessor.它对你没有任何作用.当然,很可能还有其他需要它的代码,但您没有显示.
  • CustomerService 上的 @Repository 注释是 应该用于 DAO 类,或与数据库交互的类.服务的适当注释是 @Service.
  • 您的 ICustomerRepository 上的 @Resource 注释主要是 用于标记自动装配的字段和方法.我不确定是什么让您想到将它放在您的存储库界面上,但它在那里没有做任何事情.
  • 您的存储库不应该是 @Transactional.这属于您的服务,您已经在那里得到了它,所以很好.请注意,它仍然可以与存储库上的 @Transactional 一起使用,因为它只是加入了服务启动的现有事务.
  • 再次值得注意的是,您没有使用 组件扫描,即使你有一个 @Component 相关的注解(你的服务上的 @Repository).那可能会给你带来一些问题.我没有打开组件扫描,而是在示例项目中使用 XML 手动创建了服务 bean.
  • With the code as given, there's no need for the PersistenceAnnotationBeanPostProcessor that you've added to the applicationContext.xml. It's not doing anything for you. Of course, there may well be other code that needs it that you haven't shown.
  • The @Repository annotation on your CustomerService is supposed to be used on DAO classes, or classes that interact with a database. The appropriate annotation for a service is @Service.
  • The @Resource annotation on your ICustomerRepository is mostly used for marking fields and methods for autowiring. I'm not sure what made you think to put it on your repository interface, but it's not doing anything there.
  • Your repository shouldn't be @Transactional. That belongs at your service, and you've already got it there, so that's fine. Note that it still works with the @Transactional on the repository because it just joins the existing transaction started by the service.
  • It's worth noting again that you're not using component scanning, even though you have a @Component-related annotation (the @Repository on your service). That might be causing you some problems. Instead of turning on component scanning, I manually created the service bean using XML in the sample project.

所以...如果这还没有向你解释什么,如果你给我一个特定的错误,我可能可以解释你为什么会得到它,并告诉你如何做才能使它正确.

So... if this hasn't explained something to you, if you give me a specific error, I can probably explain why you're getting it and tell you what to do to make it right.

这篇关于Spring Data JPA - 注入失败 - BeanCreationException:无法自动装配字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆