Post

Netty中用了哪些设计模式?

Netty中用了哪些设计模式?

Netty 中用了哪些设计模式?

典型回答

Netty作为一个使用广泛的网络通信框架,他的代码也是值得学习的,在Netty中也用到了很多种设计模式。比如单例模式、工厂模式、责任链模式、观察者模式、策略模式、装饰者模式等。

扩展知识

单例模式

NioEventLoop 通过核心方法 select() 不断轮询注册的 I/O 事件,Netty 提供了选择策略 SelectStrategy 对象,这个对象就是个单例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
final class DefaultSelectStrategy implements SelectStrategy {

    static final SelectStrategy INSTANCE = new DefaultSelectStrategy();

    private DefaultSelectStrategy() { }

    @Override

    public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {

        return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;

    }

}

还有其中定义的异常:

1
2
3
4
5
6
7
8
public final class ReadTimeoutException extends TimeoutException {

    private static final long serialVersionUID = 169287984113283421L;

    public static final ReadTimeoutException INSTANCE = new ReadTimeoutException();

    private ReadTimeoutException() { }
}

工厂模式

工厂模式是一个比较常见的设计模式,在很多框架中都会用到,Netty也不例外,只要我们的Netty中搜索Factory,得到的类几乎都是和工厂模式有关的。

如我们前面提到的SelectStrategy也是用工厂创建的:

1
2
3
4
5
6
7
8
9
10
public final class DefaultSelectStrategyFactory implements SelectStrategyFactory {
    public static final SelectStrategyFactory INSTANCE = new DefaultSelectStrategyFactory();

    private DefaultSelectStrategyFactory() { }

    @Override
    public SelectStrategy newSelectStrategy() {
        return DefaultSelectStrategy.INSTANCE;
    }
}

装饰者模式

Netty中的WrappedByteBuf就是你对ByteBuf的装饰。来实现对他的增强:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class WrappedByteBuf extends ByteBuf {

    protected final ByteBuf buf;

    protected WrappedByteBuf(ByteBuf buf) {
        if (buf == null) {
            throw new NullPointerException("buf");
        }
        this.buf = buf;
    }

    @Override
    public final boolean hasMemoryAddress() {
        return buf.hasMemoryAddress();
    }

    //....
    
}

责任链模式

责任链在Netty中用的比较多,Netty中有大量的ChannelPipeline,而这些Pipeline就是通过责任链来驱动的。

策略模式

Netty 在多处地方使用了策略模式,例如 EventExecutorChooser 提供了不同的策略选择 NioEventLoop,newChooser() 方法会根据线程池的大小情况来动态选择取模运算的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {

    public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();

    private DefaultEventExecutorChooserFactory() { }

    @Override
    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        if (isPowerOfTwo(executors.length)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }
}

而这里的PowerOfTwoEventExecutorChooser和GenericEventExecutorChooser是是EventExecutorChooser的两种具体策略实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {
            return executors[idx.getAndIncrement() & executors.length - 1];
        }
    }

    private static final class GenericEventExecutorChooser implements EventExecutorChooser {
        // Use a 'long' counter to avoid non-round-robin behaviour at the 32-bit overflow boundary.
        // The 64-bit long solves this by placing the overflow so far into the future, that no system
        // will encounter this in practice.
        private final AtomicLong idx = new AtomicLong();
        private final EventExecutor[] executors;

        GenericEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {
            return executors[(int) Math.abs(idx.getAndIncrement() % executors.length)];
        }
    }

原文: https://www.yuque.com/hollis666/xkm7k3/qwoyddp9ci4b643c

This post is licensed under CC BY 4.0 by the author.