Spring 注释:@Component 有效,@Repository 无效
Posted
技术标签:
【中文标题】Spring 注释:@Component 有效,@Repository 无效【英文标题】:Spring annotations: @Component works, @Repository doesn't 【发布时间】:2014-09-12 13:00:06 【问题描述】:我的 spring 应用程序几乎没有问题。这是我的代码:
(存储库)
import com.maciej.entities.Etwas;
import com.maciej.repository.EtwasRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import java.util.List;
HERE IS THE PROBLEM ----- @Component works, while @Repository doesn't
public class EtwasHibernateRepository implements EtwasRepository
@PersistenceContext
private EntityManager entityManager;
@Override
public List<Etwas> findAll()
return null;
@Override
public Etwas create(Etwas etwas)
entityManager.persist(etwas);
return etwas;
@Override
public Etwas read(int id)
TypedQuery<Etwas> query = entityManager.createQuery("SELECT e FROM Etwas e WHERE e.id=:id", Etwas.class);
query.setParameter("id", id);
Etwas etwas = query.getSingleResult();
return etwas;
@Override
public Etwas update(Etwas etwas)
return null;
@Override
public boolean delete(int id)
return false;
这是我的简单服务类:
import com.maciej.entities.Etwas;
import com.maciej.repository.impl.EtwasHibernateRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class EtwasService
@Autowired
private EtwasHibernateRepository etwasHibernateRepository;
public boolean save(Etwas etwas)
etwasHibernateRepository.create(etwas);
return true;
public Etwas read(int id)
return etwasHibernateRepository.read(id);
和简单的测试类:
import com.maciej.Config;
import com.maciej.entities.Etwas;
import com.maciej.services.EtwasService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class Test
public static void main(String[] args)
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(Config.class);
Etwas etwas = acac.getBean("etwas", Etwas.class);
etwas.setSth("STATATASTAT");
EtwasService etwasService = acac.getBean("etwasService", EtwasService.class);
for(int i=0; i<=20; i++)
etwasService.save(etwas);
System.out.println(etwasService.read(7).toString());
System.out.println(etwas.getSth());
问题是,当我用@Component
注释EtwasHibernateRepository
时,一切正常。当我添加时,实际上很恰当 - @Repository
注释我得到一个堆栈跟踪:
你有什么建议我做错了什么?
ps 代码真的很简单,只是为了测试而编写的,所以不要在意:)
线程“main”中的异常 org.springframework.beans.factory.BeanCreationException:错误 创建名为“etwasService”的bean:注入自动装配 依赖失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:不能 自动装配字段:私有 com.maciej.repository.impl.EtwasHibernateRepository com.maciej.services.EtwasService.etwasHibernateRepository;嵌套的 例外是 org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 符合条件的 bean 类型 [com.maciej.repository.impl.EtwasHibernateRepository] 找到 依赖项:预计至少有 1 个符合自动装配条件的 bean 这种依赖的候选人。依赖注解: @org.springframework.beans.factory.annotation.Autowired(required=true) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) 在 org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703) 在 org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760) 在 org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482) 在 org.springframework.context.annotation.AnnotationConfigApplicationContext.(AnnotationConfigApplicationContext.java:84) 在 com.maciej.test.Test.main(Test.java:12) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 引起:org.springframework.beans.factory.BeanCreationException: 无法自动装配字段:私有 com.maciej.repository.impl.EtwasHibernateRepository com.maciej.services.EtwasService.etwasHibernateRepository;嵌套的 例外是 org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 符合条件的 bean 类型 [com.maciej.repository.impl.EtwasHibernateRepository] 找到 依赖项:预计至少有 1 个符合自动装配条件的 bean 这种依赖的候选人。依赖注解: @org.springframework.beans.factory.annotation.Autowired(required=true) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508) 在 org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289) ... 17 更多原因: org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 符合条件的 bean 类型 [com.maciej.repository.impl.EtwasHibernateRepository] 找到 依赖项:预计至少有 1 个符合自动装配条件的 bean 这种依赖的候选人。依赖注解: @org.springframework.beans.factory.annotation.Autowired(required=true) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480) ... 19 更多
更新:配置
import com.maciej.entities.Etwas;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import java.util.Properties;
@Configuration
@ComponentScan
@EnableTransactionManagement
public class Config
@Bean
public Etwas etwas()
return new Etwas();
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPackagesToScan(new String[]"com.maciej.entities");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
emf.setJpaProperties(additionalProperties());
return emf;
@Bean
public BasicDataSource dataSource()
BasicDataSource bds = new BasicDataSource();
bds.setUsername("root");
bds.setPassword("maciek");
bds.setUrl("jdbc:mysql://localhost:3306/test");
bds.setDriverClassName("com.mysql.jdbc.Driver");
return bds;
private Properties additionalProperties()
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("hibernate.format_sql", "true");
return properties;
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf)
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf); //entityManagerFactory().getObject()
return transactionManager;
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation()
return new PersistenceExceptionTranslationPostProcessor();
【问题讨论】:
【参考方案1】:问题在于您没有对接口进行编程。
@Service
@Transactional
public class EtwasService
@Autowired
private EtwasHibernateRepository etwasHibernateRepository;
自动装配的依赖是完全实现的类,而它应该是EtwasRepository
。这将使它适用于@Component
和@Repository
。除此之外,这也是正确的做法。
@Service
@Transactional
public class EtwasService
@Autowired
private EtwasRepository etwasHibernateRepository;
带有@Repository
注释的Bean 将启用自动异常翻译,这适用于AOP。默认情况下,Spring 使用基于接口的 JDK 动态代理。它将创建一个实现EtwasRepository
接口的动态类并应用aop 拦截器。这会生成 EtwasRepository
类型的 bean,而不再是 EtwasHibernateRepository
类型。
注释您的 bean @Component
时不会应用此转换。
关于您的配置的注释不需要PersistenceExceptionTranslationPostProcessor
的显式声明。这已经处理好了。
【讨论】:
所以现在我想问几个问题: 1.@Service 怎么样?我现在有没有实现接口的服务类,@Service 可以为它工作。 2.我是spring和jpa的新手,其实不知道:异常翻译是做什么的? 3.我应该为服务和存储库以及“带接口的代码”创建接口吗?@Service
目前没有应用其他行为。您的 @Transactional
确实如此,但由于您没有实现接口,因此将创建一个 cglib 代理(基于类)。一般来说,我更喜欢接口而不是类,但很多事情都会问 10 个开发人员并得到 12 个答案:)。
是的,但我想知道接口编程中的一件事:让我们看看 Spring MVC,有 @Controllers @Services 和 @Repositories。 @Controller 应该调用@Service,然后@Service 应该调用@Repository。所以:如果我为存储库类和服务类创建单独的接口,每次我想向 repo 接口添加新方法时,我也必须将它添加到服务接口。是否有任何选项或设计模式可以避免每次添加两次方法?
如果您有一个一对一的映射,要么您的服务层错误(细粒度),要么您的数据访问层错误(粗粒度)。您的服务层应该提供用例/服务,而不是简单的保存/加载/更新方法。一般来说,当存在一对一映射时,Web 层中的业务逻辑应该在服务层中。
架构是一个不同的问题,不应该在 cmets 中回答。所以接受/投票赞成这个答案(因为它回答了你的@Component
和@Repository
问题。关于基于接口的编程的优缺点在*** 上已经存在问题。以上是关于Spring 注释:@Component 有效,@Repository 无效的主要内容,如果未能解决你的问题,请参考以下文章
@Bean 和 @Component 注释是不是相同但针对 Spring Framework 中的不同目标? [复制]
Spring注解@Component@Repository@Service@Controller区别
@Bean在@Configuration和在@Component中的区别