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 中的不同目标? [复制]

以编程方式注册@Component注释类

Spring注解@Component@Repository@Service@Controller区别

@Bean在@Configuration和在@Component中的区别

Spring注解@Component@Repository@Service@Controller区别

Spring 2.5