java - spring boot 自定义启动器,在其中定义实体,而不使用@EntityScan。是否可以?

标签 java spring-boot spring-boot-starter

我正在使用 Spring Boot 的自定义启动器进行一些测试。我设法配置了除实体之外的所有内容。我尝试使用 @Import 加载 @AutoConfiguration 类中的实体,但这不起作用。相反,如果我们在启动器中使用 @EntityScan ,则会加载实体,但如果您导入此启动器并且项目中的实体依赖于启动器,则您将被迫使用 @EntityScan code> 也在其中,在我看来,这破坏了启动器的自动配置含义,因为当您导入启动器时,您不应该执行任何操作来使用它,是的,您可以覆盖默认配置,但不必强制执行任何可能声明的操作一些属性。

启动器中的自动配置类示例:

@AutoConfiguration(after = JpaRepositoriesAutoConfiguration.class)
//@AutoConfigureAfter(JpaRepositoriesAutoConfiguration.class)
@EnableJpaRepositories(basePackages = "com.example.springbootstarterexample.repository")
@Import({SomeServiceImpl.class, SomeEntityController.class /*, SomeEntity.class NOT WORKING*/})
@EntityScan(basePackages = "com.example.springbootstarterexample.domain")
public class ExampleAutoConfiguration {

}

然后,如果您在启动器的使用者中有实体,则如果其中有实体,则必须执行此操作:

@SpringBootApplication
@EntityScan(basePackages = "com.example.springbootconsumer.model")
public class SpringBootConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootConsumerApplication.class, args);
    }

}

否则我们可以从启动器中删除@EntityScan并在消费者中执行此操作:

@SpringBootApplication
@EntityScan(basePackages = {"com.example.springbootconsumer.model", "com.example.springbootstarterexample.domain"})
public class SpringBootConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootConsumerApplication.class, args);
    }

}

但这完全阻止了自动配置,因为您必须知道实体在启动器中的位置才能启动应用程序。 我写了一个example如果有兴趣的话。

编辑 尝试使用@AutoConfigurationPackage

@AutoConfiguration(after = JpaRepositoriesAutoConfiguration.class)
//@AutoConfigureAfter(JpaRepositoriesAutoConfiguration.class)
//@EnableJpaRepositories(basePackages = {"com.example.springbootstarterexample.repository"})
@AutoConfigurationPackage(basePackageClasses = {SomeEntity.class, SomeEntityRepository.class})
@Import({SomeServiceImpl.class, SomeEntityController.class /*, SomeEntity.class NOT WORKING*/})
//@EntityScan(basePackages = "com.example.springbootstarterexample.domain")
public class ExampleAutoConfiguration {

}

这样存储库就不会被实例化

Description:

Parameter 0 of constructor in com.example.springbootstarterexample.service.SomeServiceImpl required a bean of type 'com.example.springbootstarterexample.repository.SomeEntityRepository' that could not be found.


Action:

Consider defining a bean of type 'com.example.springbootstarterexample.repository.SomeEntityRepository' in your configuration.

如果我使用@EnableJpaRepositories,则会找到用于注入(inject)的存储库,但不会找到实体

@AutoConfiguration(after = JpaRepositoriesAutoConfiguration.class)
//@AutoConfigureAfter(JpaRepositoriesAutoConfiguration.class)
@EnableJpaRepositories(basePackages = {"com.example.springbootstarterexample.repository"})
@AutoConfigurationPackage(basePackageClasses = {SomeEntity.class})
@Import({SomeServiceImpl.class, SomeEntityController.class /*, SomeEntity.class NOT WORKING*/})
//@EntityScan(basePackages = "com.example.springbootstarterexample.domain")
public class ExampleAutoConfiguration {

}

错误:

Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.example.springbootstarterexample.domain.SomeEntity

使用包的名称我得到相同的结果

编辑2 @AutoConfiguration 类由META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 加载删除了@Import:

@AutoConfiguration(after = JpaRepositoriesAutoConfiguration.class)
//@AutoConfigureAfter(JpaRepositoriesAutoConfiguration.class)
//@EnableJpaRepositories(basePackages = {"com.example.springbootstarterexample.repository"})
@AutoConfigurationPackage(basePackageClasses = {SomeEntity.class, SomeServiceImpl.class, SomeEntityController.class, SomeEntityRepository.class})
//@Import({SomeServiceImpl.class, SomeEntityController.class /*, SomeEntity.class NOT WORKING*/})
//@EntityScan(basePackages = "com.example.springbootstarterexample.domain")
public class ExampleAutoConfiguration {

}

尝试向消费者注入(inject)一些东西:

Description:

Parameter 0 of constructor in com.example.springbootconsumer.SpringBootConsumerApplication required a bean of type 'com.example.springbootstarterexample.service.SomeService' that could not be found.


Action:

Consider defining a bean of type 'com.example.springbootstarterexample.service.SomeService' in your configuration.

这似乎根本没有加载任何配置。

编辑3将日志级别设置为TRACE,并将所有类放在同一个包下,ExampleAutoConfiguration类的包现在如下所示:

@AutoConfiguration(after = JpaRepositoriesAutoConfiguration.class)
//@AutoConfigureAfter(JpaRepositoriesAutoConfiguration.class)
//@EnableJpaRepositories(basePackages = {"com.example.springbootstarterexample.repository"})
@AutoConfigurationPackage
//@Import({SomeServiceImpl.class, SomeEntityController.class /*, SomeEntity.class NOT WORKING*/})
//@EntityScan(basePackages = "com.example.springbootstarterexample.domain")
public class ExampleAutoConfiguration {

}

我发现正在扫描@AutoConfiguration类的日志,但在日志中找不到包中定义的任何bean:

2022-09-08 20:03:24.495 TRACE 17132 --- [           main] a.ConfigurationClassBeanDefinitionReader : Registered bean definition for imported class 'com.example.springbootstarterexample.autoconfigure.ExampleAutoConfiguration'

如果我使用正常配置,我会看到所有 bean 都已创建

2022-09-08 22:31:34.580 TRACE 2308 --- [           main] a.ConfigurationClassBeanDefinitionReader : Registered bean definition for imported class 'com.example.springbootstarterexample.service.SomeServiceImpl'
2022-09-08 22:31:34.581 TRACE 2308 --- [           main] a.ConfigurationClassBeanDefinitionReader : Registered bean definition for imported class 'com.example.springbootstarterexample.controller.SomeEntityController'
2022-09-08 22:31:34.585 TRACE 2308 --- [           main] a.ConfigurationClassBeanDefinitionReader : Registered bean definition for imported class 'com.example.springbootstarterexample.autoconfigure.ExampleAutoConfiguration'
2022-09-08 22:31:34.685 TRACE 2308 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Spring Data JPA - Registering repository: someEntityRepository - Interface: com.example.springbootstarterexample.repository.SomeEntityRepository - Factory: org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean
2022-09-08 22:31:39.094 DEBUG 2308 --- [           main] org.hibernate.cfg.Ejb3Column             : Binding column: Ejb3DiscriminatorColumn{logicalColumnName'DTYPE', discriminatorTypeName='string'}
2022-09-08 22:31:39.112 DEBUG 2308 --- [           main] o.h.cfg.annotations.EntityBinder         : Import with entity name SomeEntity
2022-09-08 22:31:39.113 TRACE 2308 --- [           main] o.h.b.i.InFlightMetadataCollectorImpl    : Import: SomeEntity -> com.example.springbootstarterexample.domain.SomeEntity
2022-09-08 22:31:39.114 TRACE 2308 --- [           main] o.h.b.i.InFlightMetadataCollectorImpl    : Import: com.example.springbootstarterexample.domain.SomeEntity -> com.example.springbootstarterexample.domain.SomeEntity

最佳答案

终于找到了解决方案,感谢这个post 。 配置类变为:

@AutoConfigureBefore(JpaRepositoriesAutoConfiguration.class)
@EnableJpaRepositories(basePackages = {"com.example.springbootstarterexample.repository"})
@Import({SomeServiceImpl.class, SomeEntityController.class, StarterEntityRegistrar.class /*, SomeEntity.class NOT WORKING*/})
public class ExampleAutoConfiguration {

}

以及实体的注册商:

public class StarterEntityRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AutoConfigurationPackages.register(registry, SomeEntity.class.getPackageName());
    }

}

工作中example

您可以使用注册方法添加您需要的所有包:

Programmatically registers the auto-configuration package names. Subsequentinvocations will add the given package names to those that have already beenregistered. You can use this method to manually define the base packages that willbe used for a given BeanDefinitionRegistry. Generally it's recommended thatyou don't call this method directly, but instead rely on the default conventionwhere the package name is set from your @EnableAutoConfigurationconfiguration class or classes.

关于java - spring boot 自定义启动器,在其中定义实体,而不使用@EntityScan。是否可以?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73538904/

相关文章:

java - 了解 JVM GC

java - hibernate : Table doesn't get updated

Spring boot服务启动错误java.lang.NoSuchFieldError : INSTANCE

spring - NoHandlerForCommandException 与 axon-spring-boot-starter

java - 如何从innersource引用一个项目?

java - 使用 matlabcontrol API 在 Netbeans 中调用从 Java 调用 matlab 函数

java - 很好地处理数据库约束错误

java - Axon MongoDB - 消息 ='E11000 duplicate key error collection uniqueAggregateIndex dup key: { : "101",: 0 }

spring-boot - @SpringBootTest无法自动接线JavaMailSender并引发错误

maven - 如何在 maven pom.xml 文件中拥有另一个父依赖项以及 Spring Boot 父项?