Skip to content

Commit fe4c83a

Browse files
committed
Merge pull request #16087 from Dmytro Nosan
* gh-16087: Polish "Ensure that MongoClient's EventLoopGroup is shut down during context close" Ensure that MongoClient's EventLoopGroup is shut down during context close Closes gh-16087
2 parents 02b24b6 + f20d9a6 commit fe4c83a

File tree

2 files changed

+54
-14
lines changed

2 files changed

+54
-14
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,11 +21,15 @@
2121
import javax.annotation.PreDestroy;
2222

2323
import com.mongodb.MongoClientSettings;
24+
import com.mongodb.MongoClientSettings.Builder;
2425
import com.mongodb.connection.netty.NettyStreamFactoryFactory;
2526
import com.mongodb.reactivestreams.client.MongoClient;
27+
import io.netty.channel.EventLoopGroup;
28+
import io.netty.channel.nio.NioEventLoopGroup;
2629
import io.netty.channel.socket.SocketChannel;
2730
import reactor.core.publisher.Flux;
2831

32+
import org.springframework.beans.factory.DisposableBean;
2933
import org.springframework.beans.factory.ObjectProvider;
3034
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3135
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -77,23 +81,51 @@ public MongoClient reactiveStreamsMongoClient(MongoProperties properties,
7781
}
7882

7983
@Configuration
80-
@ConditionalOnClass(SocketChannel.class)
84+
@ConditionalOnClass({ SocketChannel.class, NioEventLoopGroup.class })
8185
static class NettyDriverConfiguration {
8286

8387
@Bean
8488
@Order(Ordered.HIGHEST_PRECEDENCE)
85-
public MongoClientSettingsBuilderCustomizer nettyDriverCustomizer(
89+
public NettyDriverMongoClientSettingsBuilderCustomizer nettyDriverCustomizer(
8690
ObjectProvider<MongoClientSettings> settings) {
87-
return (builder) -> {
88-
if (!isStreamFactoryFactoryDefined(settings.getIfAvailable())) {
89-
builder.streamFactoryFactory(
90-
NettyStreamFactoryFactory.builder().build());
91-
}
92-
};
91+
return new NettyDriverMongoClientSettingsBuilderCustomizer(settings);
9392
}
9493

95-
private boolean isStreamFactoryFactoryDefined(MongoClientSettings settings) {
96-
return settings != null && settings.getStreamFactoryFactory() != null;
94+
private static final class NettyDriverMongoClientSettingsBuilderCustomizer
95+
implements MongoClientSettingsBuilderCustomizer, DisposableBean {
96+
97+
private final ObjectProvider<MongoClientSettings> settings;
98+
99+
private volatile EventLoopGroup eventLoopGroup;
100+
101+
private NettyDriverMongoClientSettingsBuilderCustomizer(
102+
ObjectProvider<MongoClientSettings> settings) {
103+
this.settings = settings;
104+
}
105+
106+
@Override
107+
public void customize(Builder builder) {
108+
if (!isStreamFactoryFactoryDefined(this.settings.getIfAvailable())) {
109+
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
110+
this.eventLoopGroup = eventLoopGroup;
111+
builder.streamFactoryFactory(NettyStreamFactoryFactory.builder()
112+
.eventLoopGroup(eventLoopGroup).build());
113+
}
114+
}
115+
116+
@Override
117+
public void destroy() {
118+
EventLoopGroup eventLoopGroup = this.eventLoopGroup;
119+
if (eventLoopGroup != null) {
120+
eventLoopGroup.shutdownGracefully().awaitUninterruptibly();
121+
this.eventLoopGroup = null;
122+
}
123+
}
124+
125+
private boolean isStreamFactoryFactoryDefined(MongoClientSettings settings) {
126+
return settings != null && settings.getStreamFactoryFactory() != null;
127+
}
128+
97129
}
98130

99131
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.mongo;
1818

1919
import java.util.concurrent.TimeUnit;
20+
import java.util.concurrent.atomic.AtomicReference;
2021

2122
import com.mongodb.MongoClientSettings;
2223
import com.mongodb.ReadPreference;
@@ -25,6 +26,7 @@
2526
import com.mongodb.connection.StreamFactoryFactory;
2627
import com.mongodb.connection.netty.NettyStreamFactoryFactory;
2728
import com.mongodb.reactivestreams.client.MongoClient;
29+
import io.netty.channel.EventLoopGroup;
2830
import org.junit.Test;
2931

3032
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -89,11 +91,17 @@ public void optionsSslConfig() {
8991

9092
@Test
9193
public void nettyStreamFactoryFactoryIsConfiguredAutomatically() {
94+
AtomicReference<EventLoopGroup> eventLoopGroupReference = new AtomicReference<>();
9295
this.contextRunner.run((context) -> {
9396
assertThat(context).hasSingleBean(MongoClient.class);
94-
assertThat(getSettings(context).getStreamFactoryFactory())
95-
.isInstanceOf(NettyStreamFactoryFactory.class);
97+
StreamFactoryFactory factory = getSettings(context).getStreamFactoryFactory();
98+
assertThat(factory).isInstanceOf(NettyStreamFactoryFactory.class);
99+
EventLoopGroup eventLoopGroup = (EventLoopGroup) ReflectionTestUtils
100+
.getField(factory, "eventLoopGroup");
101+
assertThat(eventLoopGroup.isShutdown()).isFalse();
102+
eventLoopGroupReference.set(eventLoopGroup);
96103
});
104+
assertThat(eventLoopGroupReference.get().isShutdown()).isTrue();
97105
}
98106

99107
@Test

0 commit comments

Comments
 (0)