栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java-IO系列:Netty中Channel创建过程以及与操作系统系统调用的关系

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java-IO系列:Netty中Channel创建过程以及与操作系统系统调用的关系

应用代码
public static void start() throws Exception {
        ServerBootstrap bootstrap = new ServerBootstrap();
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        bootstrap.group(boss, work)
                .handler(new LoggingHandler(LogLevel.DEBUG))
                //重点看这句Channel
                .channel(NioServerSocketChannel.class)
                .childHandler(new HttpServerInitializer());
        ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
        ...
源码 一、初始化ServerBootstrap的channelFactory属性
    public B channel(Class channelClass) {
        return channelFactory(new ReflectiveChannelFactory(
                ObjectUtil.checkNotNull(channelClass, "channelClass")
        ));
    }

这里学习下一个工厂

ReflectiveChannelFactory

public class ReflectiveChannelFactory implements ChannelFactory {

    private final Constructor constructor;

    public ReflectiveChannelFactory(Class clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }

    @Override
    public T newChannel() {
        try {
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }

    @Override
    public String toString() {
        return StringUtil.simpleClassName(ReflectiveChannelFactory.class) +
                '(' + StringUtil.simpleClassName(constructor.getDeclaringClass()) + ".class)";
    }
}

解读一下:

ChannelFactory是一个泛型接口,定义了newChannel()方法,也就是ChannelFactory的实现类要有能力构造一个new Channel。
ReflectiveChannelFactory的泛型T是Channel的子类。也就是说ReflectiveChannelFactory支持实例化Channel的子类。比如NioServerScoketChannel。

而ReflectiveChannelFactory的构造方法中,将Channel类的无参构造方法,赋值给constructor属性。
在newChannel()方法中,通过反射调用constructor无参构造方法,实例化一个Channel对象。

此处只是初始化一个ServerBootStrap对象的channelFactory属性。设置channelFactory为ReflectiveChannelFactory(NioServerSocketChannel.class)。

二、bootstrap.bind时initAndRegister过程中new Channel
final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            channel = channelFactory.newChannel();
            init(channel);
        .......

channelFactory.newChannel();
这句会调用ReflectiveChannelFactory的newChannel方法,调用NioServerSocketChannel的构造方法构造一个Channel。

NioServerSocketChannel

NioServerSocketChannel类后面单独讲

DEFAULT_SELECtOR_PROVIDER

NioServerSocketChannel.java

    private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();

SelectorProvider.java

public static SelectorProvider provider() {
        synchronized (lock) {
            if (provider != null)
                return provider;
            return AccessController.doPrivileged(
                new PrivilegedAction() {
                    public SelectorProvider run() {
                            if (loadProviderFromProperty())
                                return provider;
                            if (loadProviderAsService())
                                return provider;
                            provider = sun.nio.ch.DefaultSelectorProvider.create();
                            return provider;
                        }
                    });
        }
    }

provider中,如果SelectorProvider的provider有了就返回。
如果没有,则从系统配置中找配置的provider,如果有就实例化并返回。

System.getProperty("java.nio.channels.spi.SelectorProvider");

如果系统配置没有,则通过SPI加载配置的provider。使用了JDK的SPI能力,关键源码如下:

ServiceLoader sl =
            ServiceLoader.load(SelectorProvider.class,
                               ClassLoader.getSystemClassLoader());

如果SPI也没有配置provider,这通过jdk中DefaultSelectorProvider静态方法create()来创建provider。核心代码入下,根据运行操作系统,如果是linux则new一个EPollSelectorProvider。

public static SelectorProvider create() {
        String osname = (String)AccessController.doPrivileged(new GetPropertyAction("os.name"));
        if (osname.equals("SunOS")) {
            return createProvider("sun.nio.ch.DevPollSelectorProvider");
        } else {
            return (SelectorProvider)(osname.equals("Linux") ? createProvider("sun.nio.ch.EPollSelectorProvider") : new PollSelectorProvider());
        }
    }
EPollSelectorProvider

类关系如下
EPollSelectorProvider和PollSelectorProvider继承SelectorProviderImpl这个抽象类,实现openSelector和inheritedChannel两个方法。
区别是EPollSelectorProvider的openSelector,返回EPollSelectorImpl对象
而PollSelectorProvider返回PollSelectorImpl对象。

这两个的区别后面单独说。

NioServerSocketChannel构造方法
    public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }
    
    private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            
            //参考下文provider.openServerSocketChannel()讲解;
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException(
                    "Failed to open a server socket.", e);
        }
    }
    public NioServerSocketChannel(ServerSocketChannel channel) {
    	 //参考:AbstractNioChannel的构造方法章节
        super(null, channel, SelectionKey.OP_ACCEPT);
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }    
provider.openServerSocketChannel()

EPollSelectorImpl的openServerSocketChannel,看名字就能猜到,返回一个ServerSocketChannel。当然EPollSelectorImpl作为一个SelectorProvider也能获取UDP等。

public ServerSocketChannel openServerSocketChannel() throws IOException {
        return new ServerSocketChannelImpl(this);
    }
ServerSocketChannelImpl
    ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
        super(sp);
        this.fd =  Net.serverSocket(true);
        this.fdVal = IOUtil.fdVal(fd);
        this.state = ST_INUSE;
    }

Net.java

    static FileDescriptor serverSocket(boolean stream) {
        return IOUtil.newFD(socket0(isIPv6Available(), stream, true));
    }

    // Due to oddities SO_REUSEADDR on windows reuse is ignored
    private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse);

可见ServerSocketChannelImpl构造方法中,Net.serverSocket(true);
会调用native的方法,最终会进行socket函数的系统调用。并返回操作系统上的该socket的fd号,并将fd号封装在Java中的FileDescriptor对象中。

AbstractNioChannel的构造方法
    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        try {
            ch.configureBlocking(false);
        } catch (IOException e) {
            try {
                ch.close();
            } catch (IOException e2) {
                logger.warn(
                            "Failed to close a partially initialized socket.", e2);
            }

            throw new ChannelException("Failed to enter non-blocking mode.", e);
        }
    }

配置channel感兴趣的事件,并切设置channel的模式为非阻塞模式。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/672911.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号