【问题标题】:Spring Boot @Autowired custom application.propertiesSpring Boot @Autowired 自定义 application.properties
【发布时间】:2019-03-15 07:39:58
【问题描述】:

我正在尝试让我的 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 中的自动完成。

更新 1:

我查看了:Building web applications with Spring Boot and Kotlin 并在应用程序级别添加了@EnableConfigurationProperties。这也不起作用

更新 2:

完整的堆栈跟踪:

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

更新 3:

我刚刚发现当我从我的 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 的问题!

【问题讨论】:

  • 等一下……你的 gradle 配置中有这个吗? "org.springframework.boot:spring-boot-configuration-processor"
  • 是的,使用 kapt 插件

标签: spring spring-boot kotlin


【解决方案1】:

我设法让它工作:

注释

@Service
@Configuration
@EnableConfigurationProperties
@EnableTransactionManagement
class AppConfig {

应用程序属性:

@ConfigurationProperties("mt")
class ApplicationProperties {

应用类:

@SpringBootApplication
@EnableConfigurationProperties(ApplicationProperties::class)
abstract class MessageengineApplication

豆类

我需要从 AppConfig 中删除以下 Bean:

@Bean
fun placeHolderConfigurer(): PropertySourcesPlaceholderConfigurer {
    return PropertySourcesPlaceholderConfigurer()
}

【讨论】:

  • 为什么@Service@Configuration 在一个地方?这对我来说没有意义
【解决方案2】:

这应该可行:

@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" 依赖项才能使这一切正常工作。

【讨论】:

  • 你能告诉我们完整的堆栈跟踪吗?我在一个项目中尝试了上面的代码,它成功了。
  • 是的,我刚刚将它添加到主帖中。我还用这个设置创建了一个干净的项目,但它不起作用。你能提供我你的项目吗?
【解决方案3】:

@EnableConfigurationProperties 通常放在标有@Configuration 注释的类上。

在代码 sn -p class InitApp 应该标记为 @Configuration 然后你可以(我不知道 Kotlin,所以我会提供一个 java 等价物):

@Configuration
@EnableTransactionManagement
@EnableConfigurationProperties(ApplicationProperties.class)
public class InitApp {


  @Bean
  public <<BeanThatYouNeed>> kafkaConsumer(ApplicationProperties props) {
      log.info(props.getKafka().getHost());
  }
}

【讨论】:

  • 感谢您这么快回答!试过了,遗憾的是它并没有改变任何东西。从“spring.io/guides/tutorials/spring-boot-kotlin”开始,@EnableConfigurationProperties 应该放在应用程序级别,试过这个也不会改变任何东西
【解决方案4】:

class ApplicationProperties 的标题中不需要那些 @Configuration, @ConfigurationProperties("mt")
你可以使用@Value注解直接从application.properties文件中获取props

`

@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
    }
}

`

【讨论】:

    猜你喜欢
    • 2015-11-10
    • 2020-02-25
    • 2020-05-22
    • 2019-11-28
    • 1970-01-01
    • 1970-01-01
    • 2017-08-07
    • 2014-12-15
    • 1970-01-01
    相关资源
    最近更新 更多