Spring Java Config DI定义和一个("concrete interface")的JpaRepository

Spring Java Config DI defining and a ("concrete interface") of JpaRepository

我有下面的代码。

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

我有一个 "concrete interface" MySuperCoolEntityJpaRepository 实现了我上面的 MySuperCoolEntityRepositoryContract 接口和 JpaRepository。

所有这些都适用于@ComponentScan。

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

问题是当我尝试 "code up" 界面的具体内容时。 (跳到这个问题的后面。

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 "concrete interface" 又名 "really an abstract class but called an interface" 又名 "Interface Default Methods"(参见 https://dzone.com/articles/interface-default-methods-java)......

准确的错误是:

MySuperCoolEntityJpaRepository is abstract; cannot be instantiated

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

但是有了这个超酷的"just extend JpaRepository and get all kinds of default functionality".....

如何使用 Spring DI 注册具体的 JpaRepository(特别是使用 "code it up" java 配置?

.......

我试着把它变成 "class"。

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

但这需要我定义所有内置方法,例如 "findAll" 等

Spring boot 神奇地为您的接口中定义的方法提供了实现。 @EnableJpaRepositories 扫描包下的所有包以查找扩展 JpaRepository 的接口,并为其创建一个 Spring bean,该 bean 由 SimpleJpaRepository 的实现支持(spring 数据通过此 class 提供了 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);

}

相关Post:

我找到了解决方法。我不太喜欢它,但我想它有用。

我还添加了 MySuperCoolEntityBalServiceContract(你可以从下面得到这个想法),所以你知道 why/how 我需要在下面的 CompositionRoot class 中有 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);

}