【问题标题】:Entities not scanned未扫描的实体
【发布时间】:2018-06-25 23:32:28
【问题描述】:

我有一个 Maven 项目,它代表单点登录 (SSO) 服务器的数据层。其他客户端应用程序应依赖它进行用户身份验证和授权。

这是一个 .jar 存档,将由另一个 REST 项目使用,也是一个 Maven 项目。

两者都是基于 Spring Boot 2 的项目。

该项目将针对 H2 和 MySQL 数据库进行一些集成测试。

由于它是一个库,它不会自行运行。但它有一些要执行的集成测试。因此没有main 类。

用于构建和执行测试的命令是mvn clean install -Denv="test"

我的源代码树如下所示:

├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── thalasoft
    │   │           └── userdata
    │   │               ├── config
    │   │               │   ├── DatabaseConfiguration.java
    │   │               │   ├── JpaService.java
    │   │               │   └── properties
    │   │               │       ├── AbstractDatabaseProperties.java
    │   │               │       ├── DatabaseH2TestProperties.java
    │   │               │       ├── DatabaseMySQLAcceptanceProperties.java
    │   │               │       ├── DatabaseMySQLPreProdProperties.java
    │   │               │       ├── DatabaseMySQLProdProperties.java
    │   │               │       ├── DatabaseMySQLTestProperties.java
    │   │               │       ├── DatabaseOraclePreProdProperties.java
    │   │               │       ├── DatabaseOracleProdProperties.java
    │   │               │       ├── DatabaseOracleTestProperties.java
    │   │               │       ├── DatabaseProperties.java
    │   │               │       └── PropertyNames.java
    │   │               ├── dialect
    │   │               │   ├── CustomMySQL5InnoDBDialect.java
    │   │               │   └── CustomOracle10gDialect.java
    │   │               ├── exception
    │   │               │   ├── CannotDeleteEntityException.java
    │   │               │   ├── EnrichableException.java
    │   │               │   ├── EntityAlreadyExistsException.java
    │   │               │   ├── EntityNotFoundException.java
    │   │               │   └── NoEntitiesFoundException.java
    │   │               ├── jpa
    │   │               │   ├── domain
    │   │               │   │   ├── AbstractEntity.java
    │   │               │   │   ├── EmailAddress.java
    │   │               │   │   ├── User.java
    │   │               │   │   └── UserRole.java
    │   │               │   └── repository
    │   │               │       ├── GenericRepositoryImpl.java
    │   │               │       ├── GenericRepository.java
    │   │               │       ├── UserRepositoryCustom.java
    │   │               │       ├── UserRepositoryImpl.java
    │   │               │       ├── UserRepository.java
    │   │               │       ├── UserRoleRepositoryCustom.java
    │   │               │       ├── UserRoleRepositoryImpl.java
    │   │               │       └── UserRoleRepository.java
    │   │               └── service
    │   │                   ├── UserRoleServiceImpl.java
    │   │                   ├── UserRoleService.java
    │   │                   ├── UserServiceImpl.java
    │   │                   └── UserService.java
    │   └── resources
    │       ├── application.properties
    │       └── custom
    │           └── typedef.hbm.xml
    └── test
        ├── java
        │   └── com
        │       └── thalasoft
        │           └── userdata
        │               ├── assertion
        │               │   └── UserAssert.java
        │               ├── it
        │               │   ├── jpa
        │               │   │   ├── AbstractRepositoryTest.java
        │               │   │   ├── UserRepositoryTest.java
        │               │   │   └── UserRoleRepositoryTest.java
        │               │   └── service
        │               │       ├── AbstractServiceTest.java
        │               │       └── UserServiceTest.java
        │               └── ut
        │                   ├── AbstractRepositoryTest.java
        │                   └── UserRepositoryTest.java
        └── resources
            ├── h2
            │   └── data-source-test.properties
            ├── mysql
            │   ├── clean-up-before-each-test.sql
            │   └── data-source-test.properties
            └── oracle
                ├── data-source-preprod.properties
                └── data-source-test.properties

DatabaseH2TestProperties 的加载得益于另一个 Maven 工具箱项目中定义的自定义注解:

@EnvTest
@DbH2
@Configuration
@PropertySource({ "classpath:h2/data-source-test.properties" })
public class DatabaseH2TestProperties extends AbstractDatabaseProperties {

  private static Logger logger = LoggerFactory.getLogger(DatabaseH2TestProperties.class);

  public DatabaseH2TestProperties() {
    logger.debug("===========>> Loading the classpath h2/data-source-test.properties file");
  }
}

data-source-test.properties 文件包含:

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.datasource.driver-class-name=net.sf.log4jdbc.DriverSpy
spring.datasource.url=jdbc:log4jdbc:h2:file:./target/useraccounttest
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.show-sql=true

测试都是基于类的:

@ContextConfiguration(classes = { DatabaseConfiguration.class })
@RunWith(SpringRunner.class)
@Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, scripts = { "classpath:mysql/clean-up-before-each-test.sql" })
public abstract class AbstractRepositoryTest {
}

在这堂课上,我想知道我是否应该改用@SpringBootTest(classes = { DatabaseConfiguration.class })

配置完成:

@EnableAutoConfiguration
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.userdata" })
public class DatabaseConfiguration {
}

连接H2数据库成功:

02:23:56.299 [main] DEBUG jdbc.audit - 100. Connection.getMetaData() returned dbMeta74: conn99: url=jdbc:h2:file:./target/useraccounttest user=SA  com.zaxxer.hikari.pool.ProxyConnection.getMetaData(ProxyConnection.java:361)
02:23:56.299 [main] DEBUG org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator - Database ->
       name : H2
    version : 1.4.197 (2018-03-18)
      major : 1
      minor : 4
02:23:56.299 [main] DEBUG org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator - Driver ->
       name : H2 JDBC Driver
    version : 1.4.197 (2018-03-18)
      major : 1
      minor : 4
02:23:56.299 [main] DEBUG org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator - JDBC version : 4.0
02:23:56.299 [main] INFO org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
02:23:56.305 [main] DEBUG jdbc.audit - 100. Connection.clearWarnings() returned   com.zaxxer.hikari.pool.ProxyConnection.close(ProxyConnection.java:250)

但我得到了一个例外。

控制台日志的内容:

02:23:56.338 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
02:23:56.338 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Finished creating instance of bean 'com.thalasoft.userdata.config.JpaService'
02:23:56.338 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.thalasoft.userdata.config.properties.DatabaseH2TestProperties'
02:23:56.338 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'com.thalasoft.userdata.jpa.repository.GenericRepositoryImpl'
02:23:56.338 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'com.thalasoft.userdata.jpa.repository.GenericRepositoryImpl'
02:23:56.338 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
02:23:56.340 [main] WARN org.springframework.context.support.GenericApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.thalasoft.userdata.jpa.repository.GenericRepositoryImpl' defined in file [/home/stephane/dev/java/projects/user-data/target/classes/com/thalasoft/userdata/jpa/repository/GenericRepositoryImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.Class<?>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

确实,我有一个自定义的通用存储库:

@Repository
@Transactional
public class GenericRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
        implements GenericRepository<T, ID> {

    private EntityManager entityManager;

    private final Class<T> domainClass;

    public GenericRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
        this.domainClass = domainClass;
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }
}

@NoRepositoryBean
public interface GenericRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {

  public EntityManager getEntityManager();
}

它被用作:

public interface UserRepository extends GenericRepository<User, Long>, UserRepositoryCustom {
}

public interface UserRepositoryCustom {

    public User deleteByUserId(Long id) throws EntityNotFoundException;

}

public class UserRepositoryImpl implements UserRepositoryCustom {

    @Autowired
    private UserRepository userRepository;

}

感觉好像找不到泛型类型的领域类。

【问题讨论】:

    标签: spring-boot spring-data-jpa integration-testing spring-boot-test


    【解决方案1】:

    您的GenericRepository 接口和GenericRepositoryImpl 类符合custom repository implementations in Spring Data JPA 中使用的存储库片段的模式,所以我的猜测是Spring Data 正试图实例化它以供使用。我会尝试将 GenericRepositoryImpl 重命名为 AbstractGenericRepository 或使其成为抽象类,或者两者兼而有之。您也可以尝试删除 @Repository 注释 - 毕竟类 GenericRepositoryImpl 不是存储库,而是实现它的基础。

    编辑: 从您的代码看来,您似乎正在使用 GenericRepository 创建具有自定义方法的存储库,用于通过 id 删除用户。话虽如此,我相信这段代码就足够了:

    public interface UserRepository extends JpaRepository<User, Long> {
        void deleteByUserId(Long id);
    }
    

    如果您的 User 类中的字段 userId 是注释为实体 id 的字段,您甚至不需要自定义方法,因为 JpaRepository 扩展了 CrudRepository,它已经具有方法 deleteById(ID id)。

    【讨论】:

    • 我将它重命名为 Abstract... 并添加了 @EntityScan(basePackages = { "com.thalasoft.userdata.jpa" })@EnableJpaRepositories(basePackages = { "com.thalasoft.userdata.jpa" }) 注释,但现在它给出了 org.springframework.data.mapping.PropertyReferenceException: No property namedQuery found for type User 异常,我不知道这个 namedQuery 属性在哪里来自(哪里。另外,在使用 Spring Boot(使用 Spring 4)之前,我曾经有一个名为 GenericRepositoryFactoryBean 的我的另一个类,我不再拥有它了,想知道我是否需要它。
    • 我删除了我的自定义通用存储库,并按照您的建议直接使用JpaRepository,测试终于运行了!我现在只收到一个Unable to release JDBC Connection used for DDL execution 错误,但这是不相关的,而且我猜还要走得更远。
    • 我在我的 H2 url 属性中添加了一个 ;DB_CLOSE_ON_EXIT=FALSE,就像在 jdbc:log4jdbc:h2:file:./target/useraccounttest;DB_CLOSE_ON_EXIT=FALSE 中一样,它解决了上面评论中提到的连接释放问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 2021-05-25
    相关资源
    最近更新 更多