【问题标题】:Spring Java Config DI defining and a ("concrete interface") of JpaRepositorySpring Java Config DI 定义和 JpaRepository 的(“具体接口”)
【发布时间】:2020-02-24 21:28:42
【问题描述】:

我有以下代码。

请注意,我有一个接口 MySuperCoolEntityRepositoryContract。

我有一个“具体接口”MySuperCoolEntityJpaRepository,它实现了我上面的 MySuperCoolEntityRepositoryContract 接口和 JpaRepository。

所有这些都可以通过 @ComponentScan 正常工作。

我正在将我的代码更改为“java config”,也就是我可以编写我的 DI 定义的集中位置。 (在某些圈子中也称为 CompositionRoot)。

问题是当我尝试为接口“编码”具体内容时。 (跳到这个问题的后面。

package com.me.domain.jpaentities;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;

@Entity(name = "MySuperCoolEntityTableName")
public class MySuperCoolEntity implements Serializable {

    @Id
    @Column(name = "CoolSurrogateKeyColumn")
    private String coolSurrogateKey;

    @Column(name = "CoolMagicValueColumn")
    private String coolMagicValue;


    public String getCoolSurrogateKey() {
        return this.coolSurrogateKey;
    }

    public void setCoolSurrogateKey(String coolSurrogateKey) {
        this.coolSurrogateKey = coolSurrogateKey;
    }

    public String getCoolMagicValue() {
        return this.coolMagicValue;
    }

    public void setCoolMagicValue(String coolMagicValue) {
        this.coolMagicValue = coolMagicValue;
    }

}

================

package com.me.dal.repositories.interfaces;

import com.me.domain.jpaentities.MySuperCoolEntity;
import java.util.Collection;

public interface MySuperCoolEntityRepositoryContract {

    Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);

}

===========================

package com.me.dal.repositories;

import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
import com.me.domain.jpaentities.MySuperCoolEntity;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Collection;

@Repository
public interface MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract, JpaRepository<MySuperCoolEntity,String> {

    Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);

}

现在这个问题。

package com.me.myapplication.configuration;

import com.me.dal.repositories.MySuperCoolEntityJpaRepository;
import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyCompositionRoot {


    @Bean
    public MySuperCoolEntityRepositoryContract getAMySuperCoolEntityRepositoryContract()
    {
        return new MySuperCoolEntityJpaRepository();  /* << issue is here, this is an abstract class, aka, an interface with some methods defined */
    }

}

使用超酷的 JpaRepository“具体接口”又名“真正的抽象类,但称为接口”又名“接口默认方法”(参见https://dzone.com/articles/interface-default-methods-java)............

确切的错误是:

MySuperCoolEntityJpaRepository is abstract; cannot be instantiated

我确实理解错误。 MySuperCoolEntityJpaRepository 是抽象的。我明白了。

但是有了这个超酷的“只需扩展 JpaRepository 并获得各种默认功能”.....

如何使用 Spring DI 注册一个具体的 JpaRepository(特别是使用“编码”Java 配置?

............

我试着把它变成一个“类”。

public class MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract, JpaRepository<MySuperCoolEntity,String>

但这要我定义所有内置方法,如“findAll”等。

【问题讨论】:

    标签: spring-boot jpa dependency-injection spring-data-jpa jpa-2.0


    【解决方案1】:

    Spring boot 神奇地为接口中定义的方法提供了实现。 @EnableJpaRepositories 扫描包下的所有包以查找扩展 JpaRepository 的接口,并为其创建一个 Spring bean,该 bean 由 SimpleJpaRepository 的实现支持(spring data 提供了CRUD 存储库通过这个类)。

    您的接口 MySuperCoolEntityJpaRepository 扩展了接口 MySuperCoolEntityRepositoryContract ,但您只扩展了接口 MySuperCoolEntityJpaRepository 上的 JpaRepository ,这意味着 spring 只会为接口 MySuperCoolEntityJpaRepository 中的方法提供默认实现。所以试试吧:

    public interface MySuperCoolEntityRepositoryContract extends JpaRepository<MySuperCoolEntity,String>{
    
        Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
    
    }
    

    然后在您的存储库中扩展它,例如:

    @Repository
    public interface MySuperCoolEntityJpaRepository extends MySuperCoolEntityRepositoryContract {
    
        Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
    
    }
    

    相关帖子:how annotation @Repository in java spring work?

    【讨论】:

    • 这解释了默认方法(findAll 等)以及添加到 JpaRepository 方法的神奇之处。我很欣赏这种尝试。但主要是关于使用 java-config 对 DI 进行编码,而不是依赖于任何扫描。未来的读者可以看到这个链接,了解您使用默认方法获得的一些“免费赠品”:docs.spring.io/spring-data/jpa/docs/current/reference/html/…
    【解决方案2】:

    我想出了一个解决方法。我不是很喜欢它,但我想它可以工作。

    我还添加了 MySuperCoolEntityBalServiceContract(您可以从下面得到这个想法),所以您知道为什么/如何在下面的 CompositionRoot 类中拥有 getAMySuperCoolEntityRepositoryContract 方法。

    我会留下这个(未标记)作为答案,以防其他人有更好的方法,或者看到以下问题。我不喜欢 EntitiyManager 工作,但它让事情发生了变化。

    package com.me.myapplication.configuration;
    
    
    import com.me.apicore.managers.MySuperCoolEntityBalService;
    import com.me.apicore.managers.interfaces.MySuperCoolEntityBalServiceContract;
    import com.me.dal.repositories.interfaces.MySuperCoolEntityRepositoryContract;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
    import org.springframework.data.repository.core.support.RepositoryFactorySupport;
    
    import javax.inject.Inject;
    import javax.persistence.EntityManager;
    
    @Configuration
    
    public class MyCompositionRoot {
    
        @Inject
        private EntityManager entManager; /* part of the work around trick */
    
        @Bean
        public MySuperCoolEntityBalServiceContract getAMySuperCoolEntityBalServiceContract() {
            return new MySuperCoolEntityBalService(this.getAMySuperCoolEntityRepositoryContract());
        }
    
    
        @Bean
        public MySuperCoolEntityRepositoryContract getAMySuperCoolEntityRepositoryContract() {
            //return new MySuperCoolEntityJpaRepository(); /* does not work.  :(         */
            RepositoryFactorySupport factory = new JpaRepositoryFactory(entManager);
            MySuperCoolEntityRepositoryContract repository = factory.getRepository(MySuperCoolEntityRepositoryContract.class);
            return repository;
        }
    }
    

    我对此进行了调整(注意添加了 RepositoryDe​​finition 注释)

    package com.me.dal.repositories.interfaces;
    
    import com.me.domain.jpaentities.MySuperCoolEntity;
    
    import org.springframework.data.repository.RepositoryDefinition;
    
    import java.util.Collection;
    
    @RepositoryDefinition(domainClass = MySuperCoolEntity.class, idClass = String.class)
    
    public interface MySuperCoolEntityRepositoryContract {
    
        Collection<MySuperCoolEntity> findByCoolMagicValue(String coolMagicValue);
    
    }
    

    【讨论】:

      猜你喜欢
      • 2020-02-20
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-24
      • 1970-01-01
      相关资源
      最近更新 更多