do not use ServiceLoader instances across threads
This commit is contained in:
parent
d624688f08
commit
a270ea2854
6 changed files with 116 additions and 117 deletions
|
@ -1,3 +1,3 @@
|
|||
group = org.xbib
|
||||
name = net-http
|
||||
version = 4.3.0
|
||||
version = 4.4.0
|
||||
|
|
|
@ -53,8 +53,7 @@ class Https1Test {
|
|||
|
||||
@Test
|
||||
void testGoogleHttp() throws Exception {
|
||||
NettyHttpClientConfig config = new NettyHttpsClientConfig()
|
||||
.setProtocolNegotiation(true);
|
||||
NettyHttpClientConfig config = new NettyHttpsClientConfig();
|
||||
try (NettyHttpClient client = NettyHttpClient.builder()
|
||||
.setConfig(config)
|
||||
.build()) {
|
||||
|
|
|
@ -37,9 +37,7 @@ public class NettyHttpClient implements HttpClient<HttpRequest, HttpResponse>, C
|
|||
|
||||
private final AtomicBoolean closed;
|
||||
|
||||
private final HttpChannelInitializer httpChannelInitializer;
|
||||
|
||||
private final ServiceLoader<HttpChannelInitializer> httpChannelInitializerServiceLoader;
|
||||
private HttpChannelInitializer httpChannelInitializer;
|
||||
|
||||
private Pool pool;
|
||||
|
||||
|
@ -53,7 +51,6 @@ public class NettyHttpClient implements HttpClient<HttpRequest, HttpResponse>, C
|
|||
this.bootstrap = bootstrap;
|
||||
this.closed = new AtomicBoolean(false);
|
||||
this.httpChannelInitializer = builder.httpChannelInitializer;
|
||||
this.httpChannelInitializerServiceLoader = ServiceLoader.load(HttpChannelInitializer.class);
|
||||
createBoundedPool(builder.nettyHttpClientConfig, bootstrap);
|
||||
this.interactions = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
@ -209,13 +206,21 @@ public class NettyHttpClient implements HttpClient<HttpRequest, HttpResponse>, C
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* The lookup here needs to be thread-safe.
|
||||
* @param httpAddress the HTTP address for the channel initializer to look up.
|
||||
* @return the channel initializer
|
||||
*/
|
||||
private HttpChannelInitializer lookupChannelInitializer(HttpAddress httpAddress) {
|
||||
if (httpChannelInitializer != null || httpAddress == null) {
|
||||
return httpChannelInitializer;
|
||||
}
|
||||
for (HttpChannelInitializer initializer : httpChannelInitializerServiceLoader) {
|
||||
if (initializer.supports(httpAddress)) {
|
||||
return initializer;
|
||||
synchronized (this) {
|
||||
for (HttpChannelInitializer initializer : ServiceLoader.load(HttpChannelInitializer.class)) {
|
||||
if (initializer.supports(httpAddress)) {
|
||||
httpChannelInitializer = initializer;
|
||||
return initializer;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("no channel initializer found for address " + httpAddress + ", check service provider");
|
||||
|
|
|
@ -24,6 +24,8 @@ public class NettyHttpClientBuilder {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(NettyHttpClientBuilder.class.getName());
|
||||
|
||||
private static final Object lock = new Object();
|
||||
|
||||
NettyHttpClientConfig nettyHttpClientConfig;
|
||||
|
||||
ByteBufAllocator byteBufAllocator;
|
||||
|
@ -93,68 +95,65 @@ public class NettyHttpClientBuilder {
|
|||
if (byteBufAllocator == null) {
|
||||
byteBufAllocator = ByteBufAllocator.DEFAULT;
|
||||
}
|
||||
EventLoopGroup myEventLoopGroup = createEventLoopGroup(nettyHttpClientConfig, eventLoopGroup);
|
||||
Class<? extends SocketChannel> mySocketChannelClass = createChannelClass(nettyHttpClientConfig, socketChannelClass);
|
||||
Bootstrap bootstrap = createBootstrap(nettyHttpClientConfig, byteBufAllocator, myEventLoopGroup, mySocketChannelClass);
|
||||
createEventLoopGroup(nettyHttpClientConfig);
|
||||
createChannelClass(nettyHttpClientConfig);
|
||||
Bootstrap bootstrap = createBootstrap(nettyHttpClientConfig, byteBufAllocator, eventLoopGroup, socketChannelClass);
|
||||
if (nettyCustomizer != null) {
|
||||
nettyCustomizer.afterBootstrapInitialized(bootstrap);
|
||||
}
|
||||
return new NettyHttpClient(this, myEventLoopGroup, bootstrap);
|
||||
return new NettyHttpClient(this, eventLoopGroup, bootstrap);
|
||||
}
|
||||
|
||||
protected NettyHttpClientConfig createEmptyConfig() {
|
||||
return new NettyHttpClientConfig();
|
||||
}
|
||||
|
||||
private static EventLoopGroup createEventLoopGroup(NettyHttpClientConfig clientConfig,
|
||||
EventLoopGroup eventLoopGroup) {
|
||||
private void createEventLoopGroup(NettyHttpClientConfig clientConfig) {
|
||||
if (eventLoopGroup != null) {
|
||||
return eventLoopGroup;
|
||||
return;
|
||||
}
|
||||
EventLoopGroup myEventLoopGroup = null;
|
||||
ThreadFactory threadFactory = new NamedThreadFactory("org-xbib-net-http-netty-client");
|
||||
ServiceLoader<ClientTransportProvider> transportProviders = ServiceLoader.load(ClientTransportProvider.class);
|
||||
for (ClientTransportProvider serverTransportProvider : transportProviders) {
|
||||
synchronized (lock) {
|
||||
ThreadFactory threadFactory = new NamedThreadFactory("org-xbib-net-http-netty-client");
|
||||
for (ClientTransportProvider serverTransportProvider : ServiceLoader.load(ClientTransportProvider.class)) {
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "found event loop group provider = " + serverTransportProvider);
|
||||
}
|
||||
if (clientConfig.getTransportProviderName() == null || clientConfig.getTransportProviderName().equals(serverTransportProvider.getClass().getName())) {
|
||||
eventLoopGroup = serverTransportProvider.createEventLoopGroup(clientConfig.getThreadCount(), threadFactory);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (eventLoopGroup == null) {
|
||||
eventLoopGroup = new NioEventLoopGroup(clientConfig.getThreadCount(), threadFactory);
|
||||
}
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "found event loop group provider = " + serverTransportProvider);
|
||||
}
|
||||
if (clientConfig.getTransportProviderName() == null || clientConfig.getTransportProviderName().equals(serverTransportProvider.getClass().getName())) {
|
||||
myEventLoopGroup = serverTransportProvider.createEventLoopGroup(clientConfig.getThreadCount(), threadFactory);
|
||||
break;
|
||||
logger.log(Level.FINEST, "event loop group class: " + eventLoopGroup.getClass().getName());
|
||||
}
|
||||
}
|
||||
if (myEventLoopGroup == null) {
|
||||
myEventLoopGroup = new NioEventLoopGroup(clientConfig.getThreadCount(), threadFactory);
|
||||
}
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "event loop group class: " + myEventLoopGroup.getClass().getName());
|
||||
}
|
||||
return myEventLoopGroup;
|
||||
}
|
||||
|
||||
private static Class<? extends SocketChannel> createChannelClass(NettyHttpClientConfig clientConfig,
|
||||
Class<? extends SocketChannel> socketChannelClass) {
|
||||
private void createChannelClass(NettyHttpClientConfig clientConfig) {
|
||||
if (socketChannelClass != null) {
|
||||
return socketChannelClass;
|
||||
return;
|
||||
}
|
||||
Class<? extends SocketChannel> myChannelClass = null;
|
||||
ServiceLoader<ClientTransportProvider> transportProviders = ServiceLoader.load(ClientTransportProvider.class);
|
||||
for (ClientTransportProvider transportProvider : transportProviders) {
|
||||
synchronized (lock) {
|
||||
ServiceLoader<ClientTransportProvider> transportProviders = ServiceLoader.load(ClientTransportProvider.class);
|
||||
for (ClientTransportProvider transportProvider : transportProviders) {
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "found socket channel provider = " + transportProvider);
|
||||
}
|
||||
if (clientConfig.getTransportProviderName() == null || clientConfig.getTransportProviderName().equals(transportProvider.getClass().getName())) {
|
||||
socketChannelClass = transportProvider.createSocketChannelClass();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (socketChannelClass == null) {
|
||||
socketChannelClass = NioSocketChannel.class;
|
||||
}
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "found socket channel provider = " + transportProvider);
|
||||
}
|
||||
if (clientConfig.getTransportProviderName() == null || clientConfig.getTransportProviderName().equals(transportProvider.getClass().getName())) {
|
||||
myChannelClass = transportProvider.createSocketChannelClass();
|
||||
break;
|
||||
logger.log(Level.FINEST, "socket channel class: " + socketChannelClass.getName());
|
||||
}
|
||||
}
|
||||
if (myChannelClass == null) {
|
||||
myChannelClass = NioSocketChannel.class;
|
||||
}
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.log(Level.FINEST, "socket channel class: " + myChannelClass.getName());
|
||||
}
|
||||
return myChannelClass;
|
||||
}
|
||||
|
||||
private static Bootstrap createBootstrap(NettyHttpClientConfig nettyHttpClientConfig,
|
||||
|
|
|
@ -49,24 +49,18 @@ public class NettyHttpServer implements HttpServer {
|
|||
|
||||
private final Class<? extends ServerSocketChannel> socketChannelClass;
|
||||
|
||||
private final HttpChannelInitializer httpChannelInitializer;
|
||||
|
||||
private final ServiceLoader<HttpChannelInitializer> serviceLoader;
|
||||
|
||||
private final Collection<ChannelFuture> channelFutures;
|
||||
|
||||
private final Collection<Channel> channels;
|
||||
|
||||
NettyHttpServer(NettyHttpServerBuilder builder,
|
||||
EventLoopGroup parentEventLoopGroup,
|
||||
EventLoopGroup childEventLoopGroup,
|
||||
Class<? extends ServerSocketChannel> socketChannelClass) {
|
||||
private HttpChannelInitializer httpChannelInitializer;
|
||||
|
||||
NettyHttpServer(NettyHttpServerBuilder builder) {
|
||||
this.builder = builder;
|
||||
this.parentEventLoopGroup = parentEventLoopGroup;
|
||||
this.childEventLoopGroup = childEventLoopGroup;
|
||||
this.socketChannelClass = socketChannelClass;
|
||||
this.parentEventLoopGroup = builder.parentEventLoopGroup;
|
||||
this.childEventLoopGroup = builder.childEventLoopGroup;
|
||||
this.socketChannelClass = builder.socketChannelClass;
|
||||
this.httpChannelInitializer = builder.httpChannelInitializer;
|
||||
this.serviceLoader = ServiceLoader.load(HttpChannelInitializer.class);
|
||||
this.channelFutures = new ArrayList<>();
|
||||
this.channels = new ArrayList<>();
|
||||
logger.log(Level.FINE, "parent event loop group = " + parentEventLoopGroup +
|
||||
|
@ -129,7 +123,8 @@ public class NettyHttpServer implements HttpServer {
|
|||
}
|
||||
});
|
||||
channel.attr(NettyHttpServerConfig.ATTRIBUTE_HTTP_ADDRESS).set(httpAddress);
|
||||
createChannelInitializer(httpAddress).init(channel, getServer(), builder.nettyCustomizer);
|
||||
createChannelInitializer(httpAddress);
|
||||
httpChannelInitializer.init(channel, getServer(), builder.nettyCustomizer);
|
||||
}
|
||||
});
|
||||
if (getNettyHttpServerConfig().isDebug()) {
|
||||
|
@ -248,15 +243,18 @@ public class NettyHttpServer implements HttpServer {
|
|||
logger.log(Level.INFO, "server shutdown complete");
|
||||
}
|
||||
|
||||
private HttpChannelInitializer createChannelInitializer(HttpAddress address) {
|
||||
private void createChannelInitializer(HttpAddress address) {
|
||||
if (httpChannelInitializer != null && httpChannelInitializer.supports(address)) {
|
||||
return httpChannelInitializer;
|
||||
return;
|
||||
}
|
||||
for (HttpChannelInitializer httpChannelInitializer : serviceLoader) {
|
||||
if (httpChannelInitializer.supports(address)) {
|
||||
return httpChannelInitializer;
|
||||
synchronized (this) {
|
||||
for (HttpChannelInitializer httpChannelInitializer : ServiceLoader.load(HttpChannelInitializer.class)) {
|
||||
if (httpChannelInitializer.supports(address)) {
|
||||
this.httpChannelInitializer = httpChannelInitializer;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("no channel initializer found for address " + address);
|
||||
}
|
||||
throw new IllegalStateException("no channel initializer found for address " + address);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import java.util.concurrent.ThreadFactory;
|
|||
|
||||
public class NettyHttpServerBuilder implements HttpServerBuilder {
|
||||
|
||||
private static final Object lock = new Object();
|
||||
|
||||
NettyHttpServerConfig nettyHttpServerConfig;
|
||||
|
||||
Application application;
|
||||
|
@ -83,70 +85,66 @@ public class NettyHttpServerBuilder implements HttpServerBuilder {
|
|||
}
|
||||
|
||||
public NettyHttpServer build() {
|
||||
return new NettyHttpServer(this,
|
||||
createParentEventLoopGroup(nettyHttpServerConfig, parentEventLoopGroup),
|
||||
createChildEventLoopGroup(nettyHttpServerConfig, childEventLoopGroup),
|
||||
createSocketChannelClass(nettyHttpServerConfig, socketChannelClass));
|
||||
createParentEventLoopGroup(nettyHttpServerConfig);
|
||||
createChildEventLoopGroup(nettyHttpServerConfig);
|
||||
createSocketChannelClass(nettyHttpServerConfig);
|
||||
return new NettyHttpServer(this);
|
||||
}
|
||||
|
||||
private static EventLoopGroup createParentEventLoopGroup(NettyHttpServerConfig httpServerConfig,
|
||||
EventLoopGroup parentEventLoopGroup) {
|
||||
private void createParentEventLoopGroup(NettyHttpServerConfig httpServerConfig) {
|
||||
if (parentEventLoopGroup != null) {
|
||||
return parentEventLoopGroup;
|
||||
return;
|
||||
}
|
||||
EventLoopGroup eventLoopGroup = null;
|
||||
ThreadFactory threadFactory = new NamedThreadFactory("org-xbib-net-http-netty-server-parent");
|
||||
ServiceLoader<ServerTransportProvider> transportProviders = ServiceLoader.load(ServerTransportProvider.class);
|
||||
for (ServerTransportProvider serverTransportProvider : transportProviders) {
|
||||
if (httpServerConfig.getTransportProviderName() == null ||
|
||||
httpServerConfig.getTransportProviderName().equals(serverTransportProvider.getClass().getName())) {
|
||||
eventLoopGroup = serverTransportProvider.createEventLoopGroup(httpServerConfig.getParentThreadCount(),
|
||||
threadFactory);
|
||||
synchronized (lock) {
|
||||
ThreadFactory threadFactory = new NamedThreadFactory("org-xbib-net-http-netty-server-parent");
|
||||
for (ServerTransportProvider serverTransportProvider : ServiceLoader.load(ServerTransportProvider.class)) {
|
||||
if (httpServerConfig.getTransportProviderName() == null ||
|
||||
httpServerConfig.getTransportProviderName().equals(serverTransportProvider.getClass().getName())) {
|
||||
parentEventLoopGroup = serverTransportProvider.createEventLoopGroup(httpServerConfig.getParentThreadCount(),
|
||||
threadFactory);
|
||||
}
|
||||
}
|
||||
if (parentEventLoopGroup == null) {
|
||||
parentEventLoopGroup = new NioEventLoopGroup(httpServerConfig.getParentThreadCount(), threadFactory);
|
||||
}
|
||||
}
|
||||
if (eventLoopGroup == null) {
|
||||
eventLoopGroup = new NioEventLoopGroup(httpServerConfig.getParentThreadCount(), threadFactory);
|
||||
}
|
||||
return eventLoopGroup;
|
||||
}
|
||||
|
||||
private static EventLoopGroup createChildEventLoopGroup(NettyHttpServerConfig httpServerConfig,
|
||||
EventLoopGroup childEventLoopGroup) {
|
||||
private void createChildEventLoopGroup(NettyHttpServerConfig httpServerConfig) {
|
||||
if (childEventLoopGroup != null) {
|
||||
return childEventLoopGroup;
|
||||
return;
|
||||
}
|
||||
EventLoopGroup eventLoopGroup = null;
|
||||
ThreadFactory threadFactory = new NamedThreadFactory("org-xbib-net-http-netty-server-child");
|
||||
ServiceLoader<ServerTransportProvider> transportProviders = ServiceLoader.load(ServerTransportProvider.class);
|
||||
for (ServerTransportProvider serverTransportProvider : transportProviders) {
|
||||
if (httpServerConfig.getTransportProviderName() == null ||
|
||||
httpServerConfig.getTransportProviderName().equals(serverTransportProvider.getClass().getName())) {
|
||||
eventLoopGroup = serverTransportProvider.createEventLoopGroup(httpServerConfig.getChildThreadCount(),
|
||||
threadFactory);
|
||||
synchronized (this) {
|
||||
ThreadFactory threadFactory = new NamedThreadFactory("org-xbib-net-http-netty-server-child");
|
||||
ServiceLoader<ServerTransportProvider> transportProviders = ServiceLoader.load(ServerTransportProvider.class);
|
||||
for (ServerTransportProvider serverTransportProvider : transportProviders) {
|
||||
if (httpServerConfig.getTransportProviderName() == null ||
|
||||
httpServerConfig.getTransportProviderName().equals(serverTransportProvider.getClass().getName())) {
|
||||
childEventLoopGroup = serverTransportProvider.createEventLoopGroup(httpServerConfig.getChildThreadCount(),
|
||||
threadFactory);
|
||||
}
|
||||
}
|
||||
if (childEventLoopGroup == null) {
|
||||
childEventLoopGroup = new NioEventLoopGroup(httpServerConfig.getChildThreadCount(), threadFactory);
|
||||
}
|
||||
}
|
||||
if (eventLoopGroup == null) {
|
||||
eventLoopGroup = new NioEventLoopGroup(httpServerConfig.getChildThreadCount(), threadFactory);
|
||||
}
|
||||
return eventLoopGroup;
|
||||
}
|
||||
|
||||
private static Class<? extends ServerSocketChannel> createSocketChannelClass(NettyHttpServerConfig httpServerConfig,
|
||||
Class<? extends ServerSocketChannel> socketChannelClass) {
|
||||
private void createSocketChannelClass(NettyHttpServerConfig httpServerConfig) {
|
||||
if (socketChannelClass != null) {
|
||||
return socketChannelClass;
|
||||
return;
|
||||
}
|
||||
Class<? extends ServerSocketChannel> channelClass = null;
|
||||
ServiceLoader<ServerTransportProvider> transportProviders = ServiceLoader.load(ServerTransportProvider.class);
|
||||
for (ServerTransportProvider serverTransportProvider : transportProviders) {
|
||||
if (httpServerConfig.getTransportProviderName() == null || httpServerConfig.getTransportProviderName().equals(serverTransportProvider.getClass().getName())) {
|
||||
channelClass = serverTransportProvider.createServerSocketChannelClass();
|
||||
break;
|
||||
synchronized (lock) {
|
||||
ServiceLoader<ServerTransportProvider> transportProviders = ServiceLoader.load(ServerTransportProvider.class);
|
||||
for (ServerTransportProvider serverTransportProvider : transportProviders) {
|
||||
if (httpServerConfig.getTransportProviderName() == null || httpServerConfig.getTransportProviderName().equals(serverTransportProvider.getClass().getName())) {
|
||||
socketChannelClass = serverTransportProvider.createServerSocketChannelClass();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (socketChannelClass == null) {
|
||||
socketChannelClass = NioServerSocketChannel.class;
|
||||
}
|
||||
}
|
||||
if (channelClass == null) {
|
||||
channelClass = NioServerSocketChannel.class;
|
||||
}
|
||||
return channelClass;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue