通过源码查看Netty实现跨平台的特性

 

Netty是Java中最流行的一个高性能的通讯框架,被广泛应用于各个生产应用框架中,如Hadoop、Spark、Zookeeper等。Netty4.0之后的版本主要是基于JDK的NIO实现通讯,同时又绕过了JDK自带NIO的许多BUG。众所周知,JDK实现了跨平台功能,同时基于NIO实现的Netty也实现了跨平台的特性,但Netty是如何实现这个功能特性的呢?下面通过解读源码的方式进行讲解。

前提

本文讲述的Netty版本为4.1.39.Final,可在Maven工程中添加如下依赖:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.39.Final</version>
</dependency>

源码讲解

1、NioEventLoopGroup构造方法

/**
 * Create a new instance using the default number of threads, the default {@link ThreadFactory} and
 * the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
 */
public NioEventLoopGroup() {
    this(0);
}
/**
 * Create a new instance using the specified number of threads, {@link ThreadFactory} and the
 * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
 */
public NioEventLoopGroup(int nThreads) {
    this(nThreads, (Executor) null);
}
/**
 * Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the
 * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
 */
public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
    this(nThreads, threadFactory, SelectorProvider.provider());
}
//所有的构造方法都会最终调用NioEventLoopGroup(int nThreads, Executor executor)
public NioEventLoopGroup(int nThreads, Executor executor) {
    this(nThreads, executor, SelectorProvider.provider());
}

查阅NioEventLoopGroup构造方法,所有的构造方法最终都会调用NioEventLoopGroup(int nThreads, Executor executor),该构造方法中自动传入了一个参数SelectorProvider.provider()

2、SelectorProvider.provider()方法

public static SelectorProvider provider() {
    synchronized (lock) {
        if (provider != null)
            return provider;
        return AccessController.doPrivileged(
            new PrivilegedAction<SelectorProvider>() {
                public SelectorProvider run() {
                        if (loadProviderFromProperty()) //调用了loadProviderFromProperty()方法
                            return provider;
                        if (loadProviderAsService()) //调用了loadProviderAsService()方法
                            return provider;
                        provider = sun.nio.ch.DefaultSelectorProvider.create();
                        return provider;
                    }
                });
    }
}

根据上述代码中,provider为成员变量,在首次初始化NioEventLoopGroup时,provider为null。后续分别调用了loadProviderFromProperty()和loadProviderAsService()两个方法,下面分别查看两个方法:

private static boolean loadProviderFromProperty() {
    String cn = System.getProperty("java.nio.channels.spi.SelectorProvider"); //取系统参数
    if (cn == null)
        return false; //参数如果为空,则返回false
    try {
        Class<?> c = Class.forName(cn, true,
                                   ClassLoader.getSystemClassLoader());
        provider = (SelectorProvider)c.newInstance(); //通过反射实例化一个SelectorProvider
        return true; //实例化成功后返回true
    } catch (ClassNotFoundException x) {
        throw new ServiceConfigurationError(null, x);
    } catch (IllegalAccessException x) {
        throw new ServiceConfigurationError(null, x);
    } catch (InstantiationException x) {
        throw new ServiceConfigurationError(null, x);
    } catch (SecurityException x) {
        throw new ServiceConfigurationError(null, x);
    }
}

loadProviderFromProperty()方法中取系统的property参数,在系统默认的情况下,java.nio.channels.spi.SelectorProvider是为空的,因此会返回false

private static boolean loadProviderAsService() {
    ServiceLoader<SelectorProvider> sl =
        ServiceLoader.load(SelectorProvider.class,
                           ClassLoader.getSystemClassLoader()); //通过JDK自带的ServiceLoader方式进行实例化
    Iterator<SelectorProvider> i = sl.iterator();
    for (;;) {
        try {
            if (!i.hasNext())
                return false;
            provider = i.next();
            return true;
        } catch (ServiceConfigurationError sce) {
            if (sce.getCause() instanceof SecurityException) {
                // Ignore the security exception, try the next provider
                continue;
            }
            throw sce;
        }
    }
}

loadProviderAsService()方法通过JDK自带的ServiceLoader方法进行实例化,由于SelectorProvider为一个抽象类,并非接口,因此iterator为空,该方法返回false

3、DefaultSelectorProvider

SelectorProvider.provider()最终会走到sun.nio.ch.DefaultSelectorProvider.create(),查看create()方法,发现该处为Netty的精明之处,调用了JDK自带的DefaultSelectorProvider类,该类会根据不同平台实例化不同的类:

  • mac平台
public class DefaultSelectorProvider {
    private DefaultSelectorProvider() {
    }

    public static SelectorProvider create() {
        return new KQueueSelectorProvider(); //mac平台下返回的实例
    }
}
  • windows平台
public class DefaultSelectorProvider {
    private DefaultSelectorProvider() {
    }

    public static SelectorProvider create() {
        return new WindowsSelectorProvider();//windows返回的实例
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值