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 引导。
我认为你的问题在于你如何启动你的数据库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.
原来我需要让我的数据库配置 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'
}
我遇到以下错误:
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 引导。
我认为你的问题在于你如何启动你的数据库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.
原来我需要让我的数据库配置 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'
}