Postgres 中缺少 DatabaseClient spring 启动 R2dbc 应用程序

Missing DatabaseClient in Postgres spring boot R2dbc application

我遇到以下错误:

Exception: Error creating bean with name 'inventoryService' defined in URL [jar:file:/app.jar!/BOOT-INF/classes!/com/epi/services/inventory/items/InventoryService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'itemRepository': Cannot resolve reference to bean 'databaseClient' while setting bean property 'databaseClient'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'databaseClient' available


2019-06-18 18:38:41,409 INFO  [main] org.apache.juli.logging.DirectJDKLog: Stopping service [Tomcat]


WARNING: An illegal reflective access operation has occurred


WARNING: Illegal reflective access by org.apache.catalina.loader.WebappClassLoaderBase (jar:file:/app.jar!/BOOT-INF/lib/tomcat-embed-core-8.5.29.jar!/) to field java.lang.Thread.threadLocals


WARNING: Please consider reporting this to the maintainers of org.apache.catalina.loader.WebappClassLoaderBase


WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations


WARNING: All illegal access operations will be denied in a future release


2019-06-18 18:38:45,424 INFO  [main] org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener: 




Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.


2019-06-18 18:38:50,695 ERROR [main] org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter: 




***************************


APPLICATION FAILED TO START


***************************




Description:




Parameter 0 of constructor in com.epi.services.inventory.items.InventoryService required a bean named 'databaseClient' that could not be found.






Action:




Consider defining a bean named 'databaseClient' in your configuration.

我的应用程序具有以下 类 和依赖项:

主模块内部:

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-r2dbc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.r2dbc</groupId>
            <artifactId>r2dbc-postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
        </dependency>
        <dependency>
            <groupId>myGroupId</groupId>
            <artifactId>myModule.dblib</artifactId>
            <version>${project.version}</version>
        </dependency>
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectreactor</groupId>
            <artifactId>reactor-spring</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
        </dependency>
    </dependencies>

应用程序:

@SpringBootApplication(scanBasePackages = "com.pack")
@EntityScan("com.pack")
@EnableR2dbcRepositories
@Import(DatabaseConfiguration.class)
public class InventoryApplication {

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

}

服务:

@Service
@RequiredArgsConstructor
public class InventoryService {

    private final ItemRepository itemRepository;

    public Flux<ItemPojo> getAllItems() {
        return itemRepository.findAllItems()
                             .map(Item::toPojo);
    }
}

回购:

    @Repository
public interface ItemRepository extends ReactiveCrudRepository<Item, Long> {

    Flux<List<Item>> findByName(String name);

    @Query("select i from Item i")
    Flux<Item> findAllItems();

}

实体:

@Data
@Table(name = "items")
public class Item implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    public static ItemPojo toPojo(final Item items) {
        return new ItemPojo(items.id, items.name);
    }
}

myModule.dblib:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-r2dbc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.r2dbc</groupId>
            <artifactId>r2dbc-postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-r2dbc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.r2dbc</groupId>
            <artifactId>r2dbc-postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectreactor</groupId>
            <artifactId>reactor-spring</artifactId>
        </dependency>
    </dependencies>

数据库配置:

@Configuration
@EnableR2dbcRepositories
public class DatabaseConfiguration {

    @Value("${spring.data.postgres.host}") private String host;
    @Value("${spring.data.postgres.port}") private int port;
    @Value("${spring.data.postgres.database}") private String database;
    @Value("${spring.data.postgres.username}") private String username;
    @Value("${spring.data.postgres.password}") private String password;

    @Bean
    public PostgresqlConnectionFactory connectionFactory() {
            return new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder()
                                                    .host(host)
                                                    .port(port)
                                                    .database(database)
                                                    .username(username)
                                                    .password(password)
                                                    .build());
        }
}

我错过了什么?

我将无耻地插入我自己的文章,内容是关于如何开始使用 R2DBC postgres 和 spring 引导。

R2DBC getting started

我认为你的问题在于你如何启动你的数据库connectionFactory。根据文档,您需要扩展和覆盖 AbstractR2dbcConfiguration#connectionFactory

@Configuration
@EnableR2dbcRepositories
public class PostgresConfig extends AbstractR2dbcConfiguration {

    @Override
    @Bean
    public ConnectionFactory connectionFactory() {
        return new PostgresqlConnectionFactory(
                PostgresqlConnectionConfiguration.builder()
                .host("localhost")
                .port(5432)
                .username("postgres")
                .password("mysecretpassword")
                .database("myDatabase")
                .build());
    }
}

官方文档

This approach lets you use the standard io.r2dbc.spi.ConnectionFactory instance, with the container using Spring’s AbstractR2dbcConfiguration.

As compared to registering a ConnectionFactory instance directly, the configuration support has the added advantage of also providing the container with an ExceptionTranslator implementation that translates R2DBC exceptions to exceptions in Spring’s portable DataAccessException hierarchy for data access classes annotated with the @Repository annotation.

This hierarchy and the use of @Repository is described in Spring’s DAO support features.

AbstractR2dbcConfiguration registers also DatabaseClient that is required for database interaction and for Repository implementation.

Official R2DBC documentation

原来我需要让我的数据库配置 class 扩展 AbstractR2dbcConfiguration 其中包括 DatabaseClient bean。

通过 TDD 方法,我尝试使以下 TestNG 方法起作用:

@Test
@Slf4j
@SpringBootTest
class PostgresSanityTesting extends AbstractTestNGSpringContextTests{
    @Autowired
    DatabaseClient databaseClient

    void sanityCheck() {
        assert databaseClient

    }

但要到达那里,还有一些工作...

首先,我没有看到任何有效的代码,除非我强制我的 gradle 子项目使用

构建

ext['spring.version'] = '5.2.0.M2'

里面其实是在R2Dbc documentation里面叫出来的。其他依赖项中有一半来自 spring 实验性和里程碑。所以 "buyer beware"...(例如,我仍然没有看到 R2dbc 正确处理存储库 save(),以及一系列其他问题。)

关于即时编码问题:

如果设置正确,数据库客户端是配置为 AbstractR2dbcConfiguration class 一部分的 @Bean,然后 TestNg 测试将通过。

但是我发现我仍然需要创建一个@Bean,并且我通过@ConfigurationProperties 注入连接工厂参数。我将这些问题放在两个文件中,因为将 @Bean 与 AbstractR2dbcConfiguration 的 subclass 放在一起对我来说不起作用。

这是我使用的代码,用 groovy 表示。

import io.r2dbc.spi.ConnectionFactory
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories

@Configuration
class R2DbcConfiguration extends AbstractR2dbcConfiguration {

    private final ConnectionFactory connectionFactory

    R2DbcConfiguration( ConnectionFactory connectionFactory ) {
        this.connectionFactory = connectionFactory
    }
    @Override
    ConnectionFactory connectionFactory() {
        this.connectionFactory
    }
}

import io.r2dbc.postgresql.PostgresqlConnectionConfiguration
import io.r2dbc.postgresql.PostgresqlConnectionFactory
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile

@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "spring.datasource")
class PostgresConnectionConfig{
    String database
    String username
    String password
    String host
    String port

    @Bean
    PostgresqlConnectionFactory connectionFactory() {
        final def dbPort = port as Integer
        PostgresqlConnectionConfiguration config = PostgresqlConnectionConfiguration.builder() //
                .host(host)
                .port(dbPort)
                .database(database)
                .username(username)
                .password(password).build()
        PostgresqlConnectionFactory candidate = new PostgresqlConnectionFactory(config)
        candidate
    }
}

和我的一部分 application.yml

spring:
  datasource:
    url: jdbc:postgresql://127.0.0.1:5432/postgres
    driver-class-name: org.postgresql.Driver
    driverClassName: org.postgresql.Driver
    database: postgres
    host: localhost
    port: 5432
    password: pokey0
    username: postgres

以及我的子项目的摘录 build.gradle

repositories {
    maven { url "https://repo.spring.io/libs-milestone" }
}

dependencies {
    implementation group: 'org.springframework.data', name: 'spring-data-releasetrain', version: 'Lovelace-RELEASE', ext: 'pom'
    implementation group: 'org.springframework.data', name: 'spring-data-r2dbc', version: '1.0.0.M2'
    implementation group: 'io.r2dbc', name: 'r2dbc-postgresql', version: '1.0.0.M7'
    implementation('org.springframework.boot:spring-boot-starter-webflux')
    implementation('io.projectreactor:reactor-test')
    implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.5'
        implementation('org.springframework.boot:spring-boot-starter-actuator')
        testImplementation('org.springframework.boot:spring-boot-starter-test')
        implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2'
}