MongoDB和ElasticSearch弹簧启动

时间:2018-03-12 10:06:05

标签: java spring-boot elasticsearch kotlin

我正在使用Spring boot 2.0.0。请使用在Kotlin中编写的gradle和webflux,我试图让ReactiveMongoDB和Elasticsearch一起工作,我也有JWT实现。因此要验证我实现ReactiveAuthenticationManager的AuthenticationToken,如下所示:

@Component
class UserAuthenticationManager(@Inject private val service: UserService,
                                @Inject private val encoder: PasswordEncoder) : ReactiveAuthenticationManager {

    override fun authenticate(authentication: Authentication): Mono<Authentication> {
        return service.findByUsernameWithPassword(authentication.name)
                .publishOn(Schedulers.parallel())
                .filter { u -> encoder.matches(authentication.credentials as String, u.password) }
                .switchIfEmpty(Mono.defer<User> { Mono.error<User>(BadCredentialsException("Invalid Credentials")) })
                .map { u -> AuthenticationToken(u.id, u.username, u.password!!, u.roles.map { SimpleGrantedAuthority(it.name) }) }
    }

}

并启用反应式mongodb存储库我这样做了:

@Configuration
@EnableMongoAuditing(auditorAwareRef = "springSecurityAuditorAware")
@EnableReactiveMongoRepositories(
        basePackages = ["com.example.package.repository.**.nosql"],
        excludeFilters = [
            ComponentScan.Filter(
                    type = FilterType.ASSIGNABLE_TYPE,
                    value = [ElasticsearchRepository::class]
            )
        ]
)
class DatabaseConfiguration

我也像这样配置了ElasticSearchRepositories:

@Configuration
@EnableElasticsearchRepositories(
        basePackages = ["com.example.package.repository.**.search"],
        excludeFilters = [
            ComponentScan.Filter(
                    type = FilterType.ASSIGNABLE_TYPE,
                    value = [ReactiveMongoRepository::class]
            )
        ]
)
class ElasticsearchConfiguration {

    @Bean
    fun elasticsearchTemplate(client: Client, builder: Jackson2ObjectMapperBuilder): ElasticsearchTemplate {
        return ElasticsearchTemplate(client, CustomEntityMapper(builder.createXmlMapper(false).build()))
    }

    inner class CustomEntityMapper(private val objectMapper: ObjectMapper) : EntityMapper {

        init {
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
        }

        @Throws(IOException::class)
        override fun mapToString(`object`: Any): String {
            return objectMapper.writeValueAsString(`object`)
        }

        @Throws(IOException::class)
        override fun <T> mapToObject(source: String, clazz: Class<T>): T {
            return objectMapper.readValue(source, clazz)
        }
    }
}

当我运行gradle bootRun时,它会抛出以下异常:

Caused by: java.lang.IllegalStateException: availableProcessors is already set to [8], rejecting [8]
    at io.netty.util.NettyRuntime$AvailableProcessorsHolder.setAvailableProcessors(NettyRuntime.java:51)
    at io.netty.util.NettyRuntime.setAvailableProcessors(NettyRuntime.java:87)
    at org.elasticsearch.transport.netty4.Netty4Utils.setAvailableProcessors(Netty4Utils.java:85)
    at org.elasticsearch.transport.netty4.Netty4Transport.<init>(Netty4Transport.java:140)
    at org.elasticsearch.transport.Netty4Plugin.lambda$getTransports$0(Netty4Plugin.java:93)
    at org.elasticsearch.client.transport.TransportClient.buildTemplate(TransportClient.java:177)
    at org.elasticsearch.client.transport.TransportClient.<init>(TransportClient.java:268)
    at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:133)
    at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:119)
    at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:109)
    at org.springframework.data.elasticsearch.client.TransportClientFactoryBean.buildClient(TransportClientFactoryBean.java:91)
    at org.springframework.data.elasticsearch.client.TransportClientFactoryBean.afterPropertiesSet(TransportClientFactoryBean.java:86)
    at org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration.elasticsearchClient(ElasticsearchAutoConfiguration.java:59)
    at org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration$$EnhancerBySpringCGLIB$$4eba21d.CGLIB$elasticsearchClient$0(<generated>)
    at org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration$$EnhancerBySpringCGLIB$$4eba21d$$FastClassBySpringCGLIB$$bc4f5c6f.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361)
    at org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration$$EnhancerBySpringCGLIB$$4eba21d.elasticsearchClient(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 137 common frames omitted

调试时,我发现setAvailableProcessors方法在NettyRuntime中被调用两次,第一次被MongoReactiveAutoConfiguration调用,第二次被ElasticsearchAutoConfiguration调用,我得到了异常。我还发现,如果我删除了UserAuthenticationManager的实施,MongoReactiveAutoConfiguration没有调用setAvailableProcessors方法,那么一切正常,因为ElasticsearchAutoConfiguration会调用一次。为什么MongoReactiveAutoConfiguration关心ReactiveAuthenticationManager。我真的很困惑。如何在不删除UserAuthenticationManager实施的情况下解决此问题?

有帮助吗?

解决方案: 在@RomanDzhadan的帮助下,我找到了防止被动mongo db检查Netty可用处理器的方法。 问题是MongoReactiveAutoConfiguration

中的这个Bean
@Bean
@ConditionalOnMissingBean
public MongoClient reactiveStreamsMongoClient(MongoProperties properties,
Environment environment,
ObjectProvider<List<MongoClientSettingsBuilderCustomizer>> builderCustomizers) {
    ReactiveMongoClientFactory factory = new ReactiveMongoClientFactory(properties,
            environment, builderCustomizers.getIfAvailable());
    this.mongo = factory.createMongoClient(this.settings);
    return this.mongo;
}

所以我通过使用我自己的MongoClient bean定义来解决它,例如:

@Bean
fun mongoClient(): MongoClient {
    logger.debug("Configuring mongo client")
    return MongoClients.create(mongoProperties.determineUri())
}

1 个答案:

答案 0 :(得分:1)

尝试自己管理配置bean。弹簧自动配置 - 总是充满陷阱。特别是,当您尝试使用多于1个弹簧数据的实现时。 (在你的情况下,它是elasticsearch和mongo)。

框架无法为您做任何事情。所以,我建议明确地设置它。

  • 缺点:创建bean的1或2个额外类。
  • 优点:更多控制和理解您的应用程序如何运作
相关问题