
io.quarkus.netty.deployment.NettyProcessor Maven / Gradle / Ivy
package io.quarkus.netty.deployment;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Random;
import java.util.function.Supplier;
import javax.inject.Singleton;
import org.jboss.logging.Logger;
import org.jboss.logmanager.Level;
import io.netty.channel.EventLoopGroup;
import io.netty.resolver.dns.DnsServerAddressStreamProviders;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.SystemPropertyBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageSystemPropertyBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.UnsafeAccessedFieldBuildItem;
import io.quarkus.deployment.logging.LogCleanupFilterBuildItem;
import io.quarkus.netty.BossEventLoopGroup;
import io.quarkus.netty.MainEventLoopGroup;
import io.quarkus.netty.runtime.EmptyByteBufStub;
import io.quarkus.netty.runtime.NettyRecorder;
class NettyProcessor {
private static final Logger log = Logger.getLogger(NettyProcessor.class);
private static final int DEFAULT_NETTY_ALLOCATOR_MAX_ORDER = 3;
static {
InternalLoggerFactory.setDefaultFactory(new JBossNettyLoggerFactory());
}
@BuildStep
public NativeImageSystemPropertyBuildItem limitMem() {
//in native mode we limit the size of the epoll array
//if the array overflows the selector just moves the overflow to a map
return new NativeImageSystemPropertyBuildItem("sun.nio.ch.maxUpdateArraySize", "100");
}
@BuildStep
public SystemPropertyBuildItem limitArenaSize(NettyBuildTimeConfig config,
List minMaxOrderBuildItems) {
String maxOrder = calculateMaxOrder(config.allocatorMaxOrder, minMaxOrderBuildItems, true);
//in native mode we limit the size of the epoll array
//if the array overflows the selector just moves the overflow to a map
return new SystemPropertyBuildItem("io.netty.allocator.maxOrder", maxOrder);
}
@BuildStep
public SystemPropertyBuildItem setNettyMachineId() {
// we set the io.netty.machineId system property so to prevent potential
// slowness when generating/inferring the default machine id in io.netty.channel.DefaultChannelId
// implementation, which iterates over the NetworkInterfaces to determine the "best" machine id
// borrowed from io.netty.util.internal.MacAddressUtil.EUI64_MAC_ADDRESS_LENGTH
final int EUI64_MAC_ADDRESS_LENGTH = 8;
final byte[] machineIdBytes = new byte[EUI64_MAC_ADDRESS_LENGTH];
new Random().nextBytes(machineIdBytes);
final String nettyMachineId = io.netty.util.internal.MacAddressUtil.formatAddress(machineIdBytes);
return new SystemPropertyBuildItem("io.netty.machineId", nettyMachineId);
}
@BuildStep
NativeImageConfigBuildItem build(
NettyBuildTimeConfig config,
BuildProducer reflectiveClass,
List minMaxOrderBuildItems) {
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, "io.netty.channel.socket.nio.NioSocketChannel"));
reflectiveClass
.produce(new ReflectiveClassBuildItem(false, false, "io.netty.channel.socket.nio.NioServerSocketChannel"));
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, "io.netty.channel.socket.nio.NioDatagramChannel"));
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, "java.util.LinkedHashMap"));
reflectiveClass.produce(new ReflectiveClassBuildItem(true, true, "sun.nio.ch.SelectorImpl"));
String maxOrder = calculateMaxOrder(config.allocatorMaxOrder, minMaxOrderBuildItems, false);
NativeImageConfigBuildItem.Builder builder = NativeImageConfigBuildItem.builder()
//.addNativeImageSystemProperty("io.netty.noUnsafe", "true")
// Use small chunks to avoid a lot of wasted space. Default is 16mb * arenas (derived from core count)
// Since buffers are cached to threads, the malloc overhead is temporary anyway
.addNativeImageSystemProperty("io.netty.allocator.maxOrder", maxOrder)
.addRuntimeInitializedClass("io.netty.handler.ssl.JdkNpnApplicationProtocolNegotiator")
.addRuntimeInitializedClass("io.netty.handler.ssl.ConscryptAlpnSslEngine")
.addRuntimeInitializedClass("io.netty.handler.ssl.ReferenceCountedOpenSslEngine")
.addRuntimeInitializedClass("io.netty.handler.ssl.ReferenceCountedOpenSslContext")
.addRuntimeInitializedClass("io.netty.handler.ssl.ReferenceCountedOpenSslClientContext")
.addRuntimeInitializedClass("io.netty.handler.ssl.util.ThreadLocalInsecureRandom")
.addRuntimeInitializedClass("io.netty.buffer.ByteBufUtil$HexUtil")
.addRuntimeInitializedClass("io.netty.buffer.PooledByteBufAllocator")
.addRuntimeInitializedClass("io.netty.buffer.ByteBufAllocator")
.addRuntimeInitializedClass("io.netty.buffer.ByteBufUtil")
// The default channel id uses the process id, it should not be cached in the native image.
.addRuntimeInitializedClass("io.netty.channel.DefaultChannelId")
.addNativeImageSystemProperty("io.netty.leakDetection.level", "DISABLED");
if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.handler.codec.http.HttpObjectEncoder")) {
builder
.addRuntimeInitializedClass("io.netty.handler.codec.http.HttpObjectEncoder")
.addRuntimeInitializedClass("io.netty.handler.codec.http.websocketx.extensions.compression.DeflateDecoder")
.addRuntimeInitializedClass("io.netty.handler.codec.http.websocketx.WebSocket00FrameEncoder")
.addRuntimeInitializedClass("io.netty.handler.codec.compression.ZstdOptions")
.addRuntimeInitializedClass("io.netty.handler.codec.compression.BrotliOptions");
} else {
log.debug("Not registering Netty HTTP classes as they were not found");
}
if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.handler.codec.http2.Http2CodecUtil")) {
builder
.addRuntimeInitializedClass("io.netty.handler.codec.http2.Http2CodecUtil")
.addRuntimeInitializedClass("io.netty.handler.codec.http2.Http2ClientUpgradeCodec")
.addRuntimeInitializedClass("io.netty.handler.codec.http2.DefaultHttp2FrameWriter")
.addRuntimeInitializedClass("io.netty.handler.codec.http2.Http2ConnectionHandler");
} else {
log.debug("Not registering Netty HTTP2 classes as they were not found");
}
if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.channel.unix.UnixChannel")) {
builder.addRuntimeInitializedClass("io.netty.channel.unix.Errors")
.addRuntimeInitializedClass("io.netty.channel.unix.FileDescriptor")
.addRuntimeInitializedClass("io.netty.channel.unix.IovArray")
.addRuntimeInitializedClass("io.netty.channel.unix.Limits");
} else {
log.debug("Not registering Netty native unix classes as they were not found");
}
if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.channel.epoll.EpollMode")) {
builder.addRuntimeInitializedClass("io.netty.channel.epoll.Epoll")
.addRuntimeInitializedClass("io.netty.channel.epoll.EpollEventArray")
.addRuntimeInitializedClass("io.netty.channel.epoll.EpollEventLoop")
.addRuntimeInitializedClass("io.netty.channel.epoll.Native");
} else {
log.debug("Not registering Netty native epoll classes as they were not found");
}
if (QuarkusClassLoader.isClassPresentAtRuntime("io.netty.channel.kqueue.AcceptFilter")) {
builder.addRuntimeInitializedClass("io.netty.channel.kqueue.KQueue")
.addRuntimeInitializedClass("io.netty.channel.kqueue.KQueueEventArray")
.addRuntimeInitializedClass("io.netty.channel.kqueue.KQueueEventLoop")
.addRuntimeInitializedClass("io.netty.channel.kqueue.Native");
} else {
log.debug("Not registering Netty native kqueue classes as they were not found");
}
return builder //TODO: make configurable
.build();
}
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
public void eagerlyInitClass(NettyRecorder recorder) {
//see https://github.com/quarkusio/quarkus/issues/3663
//this class is slow to initialize, we make sure that we do it eagerly
//before it blocks the IO thread and causes a warning
recorder.eagerlyInitChannelId();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void registerEventLoopBeans(BuildProducer syntheticBeans,
Optional loopSupplierBuildItem,
NettyRecorder recorder) {
Supplier
© 2015 - 2025 Weber Informatics LLC | Privacy Policy