从Spring Boot 2.0.6
/ Spring Cloud Finchley.RELEASE
更新到Spring Boot 2.1.3
/ Spring Cloud Greenwich.SR1
之后,我遇到了一个非常奇怪的配置/组件扫描问题。
应用程序的结构如下:
主应用程序带有@SpringBootApplication(scanBasePackages = {"com.app.libs", "com.app"})
注释,其中com.app
软件包是main-application
下的软件包,而com.app.libs
是libs的软件包。
commons-lib
配置只是一个框架风格的库,具有以下主要配置入口点:
package com.app.libs.commons
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(CommonsConfiguration.class)
public @interface EnableCommons {
}
CommonsConfiguration
具有:
package com.app.libs.commons.config
@Configuration
@ConditionalOnProperty(value = "com.app.config.commons", matchIfMissing = true)
@ComponentScan(basePackages = "com.app.libs.commons")
public class FrameworkConfiguration {
这样,我基本上可以在我的main-application
中注释一个配置类,并让它拾取普通的bean。
使用Spring Cloud Stream的messaging-lib
配置具有以下配置:
@Configuration
@Import({ CustomBinding.class })
@PropertySource("classpath:kafka.properties")
@EnableBinding(Source.class)
@EnableAutoConfiguration
public class BindingConfiguration {
}
云流配置如下:
spring.cloud.stream.bindings.output.destination=${spring.application.name}
spring.cloud.stream.kafka.bindings.output.producer.sync=true
spring.cloud.stream.default.group=${spring.application.name}
spring.cloud.stream.default.producer.partitionCount=9
spring.cloud.stream.default.producer.partitionKeyExpression=headers.entityId
spring.cloud.stream.kafka.binder.autoAddPartitions=true
spring.cloud.stream.kafka.binder.autoCreateTopics=false
启动应用程序时,会产生以下错误消息:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to bind properties under 'spring.cloud.stream.default.producer.partition-key-expression' to org.springframework.expression.Expression:
Property: spring.cloud.stream.default.producer.partitionkeyexpression
Value: headers.entityId
Origin: "spring.cloud.stream.default.producer.partitionKeyExpression" from property source "class path resource [kafka.properties]"
Reason: No converter found capable of converting from type [java.lang.String] to type [@com.fasterxml.jackson.databind.annotation.JsonSerialize org.springframework.expression.Expression]
Action:
Update your application's configuration
在仔细研究了源代码之后,我注意到所讨论的SpelConverter
是应该在SpelExpressionConverterConfiguration
中初始化的那个。确实,如果我将@Import({ SpelExpressionConverterConfiguration.class })
或@Import({ BindingServiceConfiguration })
(导入@Configuration
的{{1}}类添加到我的SpelExpressionConverterConfiguration
中,则转换器似乎已初始化。但是,然后会产生另一个错误:
BindingConfiguration
我不太确定发生了什么。调试时,似乎同时加载了***************************
APPLICATION FAILED TO START
***************************
Description:
A component required a bean of type 'org.springframework.messaging.core.DestinationResolver' that could not be found.
The following candidates were found but could not be injected:
- Bean method 'binderAwareChannelResolver' in 'BindingServiceConfiguration' not loaded because @ConditionalOnBean (types: org.springframework.cloud.stream.binder.BinderTypeRegistry; SearchStrategy: current) did not find any beans of type org.springframework.cloud.stream.binder.BinderTypeRegistry
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.messaging.core.DestinationResolver' in your configuration.
和BindingBeansRegistrar
(通过BinderFactoryConfiguration
导入的类),但是没有扫描发生,而其余的组件扫描似乎都没有发生。
我曾尝试自己导入配置类和/或扫描程序包,但是在两种情况下,我都仍然缺少@EnableBinding
bean,尽管它应该已经初始化。
我注意到,在更新之前,还存在一些问题:我还必须手动导入DestinationResolver
,BindingServiceConfiguration
和BinderFactoryConfiguration
。
有人会指出导致此问题的原因吗?
编辑:以下是SpelExpressionConverterConfiguration
个文件(为简洁起见,其中有些省略了):
应用程序build.grade
build.gradle
apply from: new File(project(':scripts').projectDir, '/service-impl.gradle')
dependencies {
implementation project(':dependency-A')
implementation project(':dependency-B')
implementation project(':messaging-library')
testImplementation 'org.springframework.cloud:spring-cloud-stream-test-support'
}
内容:
service-impl.gradle
公用库buildscript {
apply from: new File(project(':buildscripts').projectDir, '/repositories.gradle') // Repository definitions
apply from: new File(project(':buildscripts').projectDir, '/dm-boot.gradle') // DM via spring boot plugin
apply from: new File(project(':buildscripts').projectDir, '/dm-versions.gradle') // DM versions
}
configurations {
all*.exclude module: 'spring-boot-starter-tomcat'
all*.exclude group: 'org.apache.bval'
}
artifacts {
archives bootJar
}
dependencies {
compileOnly 'org.projectlombok:lombok'
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-jetty'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.springframework.boot:spring-boot-starter-cache'
compile 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
compile 'org.springframework.cloud:spring-cloud-starter-config'
testCompile 'junit:junit'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompileOnly 'org.projectlombok:lombok'
compile 'net.logstash.logback:logstash-logback-encoder'
}
build.gradle
消息传递库apply from: new File(project(':buildscripts').projectDir, '/repositories.gradle') // Repository definitions
apply from: new File(project(':buildscripts').projectDir, '/dm-plain.gradle') // DM via spring boot plugin
apply from: new File(project(':buildscripts').projectDir, '/dm-versions.gradle') // DM versions
dependencies {
api 'com.restfb:restfb:2.3.0'
api 'commons-io:commons-io'
implementation 'com.jcraft:jsch:0.1.54'
//lombok
compileOnly 'org.projectlombok:lombok'
//spring
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-jetty'
implementation 'org.springframework.boot:spring-boot-starter-security'
api 'org.springframework.security:spring-security-core'
api 'org.springframework.security:spring-security-web'
api 'org.springframework:spring-jdbc'
api 'org.springframework.boot:spring-boot-starter-actuator'
//thrift modules
compileOnly 'com.facebook.swift:swift-codec'
compileOnly 'com.facebook.swift:swift-service'
//db modules
api 'org.postgresql:postgresql'
api 'org.flywaydb:flyway-core'
api 'com.zaxxer:HikariCP'
api 'org.jooq:jooq'
//embedded pg modules
compileOnly 'com.opentable.components:otj-pg-embedded'
api group: 'net.minidev', name: 'json-smart', version: '2.2.1'
api group: 'org.json', name: 'json', version: '20140107'
//tests
testImplementation 'junit:junit'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'com.opentable.components:otj-pg-embedded'
testImplementation 'org.springframework.security:spring-security-core'
testImplementation 'org.springframework.security:spring-security-web'
testImplementation 'org.springframework.security:spring-security-config'
testImplementation 'org.springframework:spring-jdbc'
testImplementation 'org.springframework.boot:spring-boot-starter-actuator'
testImplementation 'org.apache.sshd:sshd-core:1.7.0' // sftpFileTransfer testing - embedded sftp server
testCompileOnly 'org.projectlombok:lombok'
testCompileOnly 'javax.servlet:javax.servlet-api'
}
(用作独立的库,因此不使用上述build.gradle
文件)
.gradle
我试图忽略我认为不相关的任何文件。