我正在尝试让custon application.properties字段在kotlin spring boot应用程序中工作。
我当前的设置:
ApplicationProperties.kt:
@Configuration
@ConfigurationProperties("mt")
class ApplicationProperties {
var initDatabase: Boolean? = null
val kafka = Kafka()
class Kafka {
lateinit var host: String
lateinit var port: String
}
}
application.properties:
mt.kafka.host=localhost
mt.kafka.port=9092
mt.init-database=true
还有一个我想使用我的应用程序的类: InitApp.kt
@Component
@EnableTransactionManagement
@EnableConfigurationProperties(ApplicationProperties::class)
class InitApp {
@Autowired
lateinit var conf: ApplicationProperties
@Bean
fun createKafkaConsumer() {
log.info("${conf.kafka.host}")
}
}
不幸的是,这不起作用,因为我得到了:
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property conf has not been initialized
我遵循了此“指南” Bootiful Kotlin by Sébastien Deleuze and Josh Long @ Spring I/O 2018,并且正在使用以下版本:
kotlinVersion = '1.2.51'
springBootVersion = '2.0.5.RELEASE'
apply plugin: 'kotlin-kapt'
在我的build.gradle中,但这应该不会与@Autowired
混淆,因为据我所知,这是为了在我的application.properties中自动完成。
我查看了Building web applications with Spring Boot and Kotlin,并在应用程序级别添加了@EnableConfigurationProperties
。这也不起作用
完整的堆栈跟踪:
2018-10-10 16:17:53.058 ERROR 23619 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'producerFactory' defined in class path resource [de/mikatiming/de/test/InitApp.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.kafka.core.ProducerFactory]: Factory method 'producerFactory' threw exception; nested exception is kotlin.UninitializedPropertyAccessException: lateinit property applicationProperties has not been initialized
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:590) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1247) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1096) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:780) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:333) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1277) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1265) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
at de.mikatiming.de.test.TestApplicationKt.main(TestApplication.kt:15) [main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_172]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_172]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_172]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_172]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.0.5.RELEASE.jar:2.0.5.RELEASE]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.kafka.core.ProducerFactory]: Factory method 'producerFactory' threw exception; nested exception is kotlin.UninitializedPropertyAccessException: lateinit property applicationProperties has not been initialized
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:582) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
... 23 common frames omitted
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property applicationProperties has not been initialized
at de.mikatiming.de.test.InitApp.getApplicationProperties(InitApp.kt:36) ~[main/:na]
at de.mikatiming.de.test.InitApp.producerFactory(InitApp.kt:58) ~[main/:na]
at de.mikatiming.de.test.InitApp$$EnhancerBySpringCGLIB$$c3b698bb.CGLIB$producerFactory$10(<generated>) ~[main/:na]
at de.mikatiming.de.test.InitApp$$EnhancerBySpringCGLIB$$c3b698bb$$FastClassBySpringCGLIB$$b315799f.invoke(<generated>) ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:365) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
at de.mikatiming.de.test.InitApp$$EnhancerBySpringCGLIB$$c3b698bb.producerFactory(<generated>) ~[main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_172]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_172]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_172]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_172]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.0.9.RELEASE.jar:5.0.9.RELEASE]
... 24 common frames omitted
我刚刚发现,当我从InitApp中删除特定的bean时:
@Bean
fun placeHolderConfigurer(): PropertySourcesPlaceholderConfigurer {
return PropertySourcesPlaceholderConfigurer()
}
我收到其他错误消息:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'de.mikatiming.messageengine.configuration.ApplicationProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
所以看来这是该bean的问题!
答案 0 :(得分:1)
我设法使其正常工作:
@Service
@Configuration
@EnableConfigurationProperties
@EnableTransactionManagement
class AppConfig {
ApplicationProperties:
@ConfigurationProperties("mt")
class ApplicationProperties {
ApplicationClass:
@SpringBootApplication
@EnableConfigurationProperties(ApplicationProperties::class)
abstract class MessageengineApplication
我需要从AppConfig中删除以下Bean:
@Bean
fun placeHolderConfigurer(): PropertySourcesPlaceholderConfigurer {
return PropertySourcesPlaceholderConfigurer()
}
答案 1 :(得分:0)
这应该有效:
@Component
@EnableTransactionManagement
@Configuration
@EnableConfigurationProperties(ApplicationProperties::class)
class InitApp {
@Autowired
lateinit var conf: ApplicationProperties
// ...
}
@ConfigurationProperties("mt")
class ApplicationProperties {
var initDatabase: Boolean? = null
val kafka = Kafka()
class Kafka {
lateinit var host: String
lateinit var port: String
}
}
请注意,您需要将@Configuration
放在InitApp
上,而不是ApplicationProperties
上。
我的build.gradle
中也有这些内容:
apply plugin: 'kotlin-spring'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
depencencies {
compile "org.springframework.boot:spring-boot-starter-web"
compileOnly "org.springframework.boot:spring-boot-configuration-processor"
}
dependencyManagement {
imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") }
}
您需要适当的"org.springframework.boot:spring-boot-configuration-processor"
依赖关系才能使整个过程正常运行。
答案 2 :(得分:-1)
@EnableConfigurationProperties
通常放在标有@Configuration
注释的类上。
在代码段class InitApp
中应标记为@Configuration
,然后就可以了(我不知道Kotlin,所以我将提供与Java等效的代码):
@Configuration
@EnableTransactionManagement
@EnableConfigurationProperties(ApplicationProperties.class)
public class InitApp {
@Bean
public <<BeanThatYouNeed>> kafkaConsumer(ApplicationProperties props) {
log.info(props.getKafka().getHost());
}
}
答案 3 :(得分:-1)
您不需要@Configuration, @ConfigurationProperties("mt")
标头中的那些class ApplicationProperties
您可以使用@Value批注直接从application.properties文件获取道具
`
@Component
@EnableTransactionManagement
class InitApp {
@Autowired
lateinit var conf: ApplicationProperties
@Bean
fun createKafkaConsumer(@Value("${mt.kafka.host}") String host,
@Value("${mt.kafka.host}") String port) {
//you have host, port now
}
}
`