10 Design Patterns
10.1 Singleton Model
Three principles: global only one instance (private construction method), static, avoid multi-threaded synchronized creation (static, synchronized)
Examples: ReadTimeoutException, MqttEncoder
ReadTimeoutException:
public final class ReadTimeoutException extends TimeoutException { private static final long serialVersionUID = 169287984113283421L; public static final ReadTimeoutException INSTANCE = new ReadTimeoutException(); private ReadTimeoutException() { } }
The same is true of MqttEncoder.
Because this is a singleton, add @Sharable
@Sharable: https://blog.csdn.net/zhailuxu/article/details/83472632
10.2 Strategy Model
Encapsulating a series of replaceable algorithm families to support dynamic selection of a strategy
Default Event Executor Chooser Factory # new Chooser implements the policy pattern and chooses different policies according to the length of the NioEventLoop array
public EventExecutorChooser newChooser(EventExecutor[] executors) { if (isPowerOfTwo(executors.length)) { return new PowerOfTowEventExecutorChooser(executors); } else { return new GenericEventExecutorChooser(executors); } }
10.3 Decorator Model
The decorator and the decorated inherit the same interface (because it is to strengthen the same method), and the decorator dynamically modifies the decorated's behavior (through combination).
WrappedByteBuf,UnReleaseableByteBuf,SimpleLeakAwareByteBuf
WrappedByteBuf inherits from ByteBuf and can be regarded as the same interface. There is a decorated ByteBuf inside. Most of the methods are delegated to the decorated ByteBuf.
Two subclasses of WrappedByteBuf, UnReleaseable ByteBuf and SimpleLeak AwareByteBuf, such as rewriting release methods (the former does not need to be released, and the latter adds memory leak detection)
class WrappedByteBuf extends ByteBuf { protected final ByteBuf buf; }
final class UnreleasableByteBuf extends WrappedByteBuf { public boolean release() { return false; } }
final class SimpleLeakAwareByteBuf extends WrappedByteBuf { @Override public boolean release(int decrement) { boolean deallocated = super.release(decrement); if (deallocated) { leak.close(); } return deallocated; } }
10.4 Observer Model
Observers and observers, observers subscribe to messages, observers publish messages, subscriptions can be received, cancelled subscriptions can not be received.
The writeAndFlush method is the implementation of this pattern:
public void write(NioSocketChannel channel, Object object) { ChannelFuture channelFuture = channel.writeAndFlush(object);//Create the Observed channelFuture.addListener(future -> {//AddiListener is adding observers. if (future.isSuccess()) {//When the writeAndFlush method is finished, it can be judged by isSuccess. } else { } }); channelFuture.addListener(future -> { if (future.isSuccess()) { } else { } }); }
In the process of writing AndFlush, there is the following code, newPromise is to create the observer
public ChannelFuture writeAndFlush(Object msg) { return writeAndFlush(msg, newPromise()); }
Save the observer through an array
10.5 iterator mode
There is an iterator interface to access the various objects in the container
Implementation of Composite ByteBuf (zero copy):
Use code:
public static void main(String[] args) { ByteBuf header = Unpooled.wrappedBuffer(new byte[]{1, 2, 3}); ByteBuf body = Unpooled.wrappedBuffer(new byte[]{4, 5, 6}); ByteBuf merge = merge(header, body); merge.forEachByte(value -> { System.out.println(value); return true; }); } public static ByteBuf merge(ByteBuf header, ByteBuf body) { CompositeByteBuf byteBuf = ByteBufAllocator.DEFAULT.compositeBuffer(2); byteBuf.addComponent(true, header); byteBuf.addComponent(true, body); return byteBuf; }
This code adds two ByteBuf s together, and forEachByte implements the iterator pattern. So how do you say it's a zero copy?
The implementation of forEachByte is in AbstractByteBuf, which has such a piece of code:
@Override public int forEachByte(ByteProcessor processor) { ensureAccessible(); try { return forEachByteAsc0(readerIndex, writerIndex, processor); } catch (Exception e) { PlatformDependent.throwException(e); return -1; } }
Start with reader Index and read to write Index:
private int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception { for (; start < end; ++start) { if (!processor.process(_getByte(start))) { return start; } } return -1; }
Look at the implementation of _getByte and find Composite ByteBuf's:
@Override protected byte _getByte(int index) { Component c = findComponent(index);//Find the component corresponding to the index, namely the added header and body return c.buf.getByte(index - c.offset); }
In fact, the ByteBuf to be merged is added to Composite ByteBuf.
If other classes iterate, all data will be copied, such as ByteBufAllocator.DEFAULT.ioBuffer()
10.6 Chain of Responsibility Model
Definition: Give multiple objects the opportunity to process requests, thus avoiding the coupling between the sender and the recipient of the request, linking the object into a chain and passing the request along the chain until one object processes it.
Many filter s in java, whether to continue to pass down, are implemented by return true or return method.
Four elements of the responsibility chain model:
1 Responsibility Processor Interface
2 Create chains, add and delete responsibility processor interfaces
3 Context
Because the responsible processor interface needs to be context-aware when dealing with events to get the objects it needs.
In addition
Chain termination mechanism.
channelHandler and Pipline constitute the responsibility chain model:
1.ChannelHandler is the responsible processor interface. ChannelInboundHandler and ChannelOuntboundHandler are its two enhancements.
2. Channel Pipeline is the creation of a chain, which defines methods to add and remove the interface of the responsible processor, such as add and remove.
3.ChannelHandlerContext is the context. When channelHandler is added to the chain, it will be encapsulated as ChannelHandlerContext.
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker { //Return the channel bound by this chain Channel channel(); //Return the executor to perform the task, which is the NioEventLoop corresponding to channel EventExecutor executor(); ... }
4. Chain of Liability Termination Mechanism
Customize an InBoundHandlerC
public class InBoundHandlerC extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("InBoundHandlerC: " + msg); ctx.fireChannelRead(msg); } }
The ctx.fiteChannelRead method is designed to pass on responsibility. If the comment is omitted, the message will not be delivered.
If you do not override the channelRead method, the ChannelInboundHandlerAdapter#channelRead method will also be passed by default:
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.fireChannelRead(msg); }
Finally, how does the message go down step by step? Look at the AbstractChannelHandlerContext#fireChannelRead method:
@Override public ChannelHandlerContext fireChannelRead(final Object msg) { invokeChannelRead(findContextInbound(), msg); return this; }
findContextInbound():
private AbstractChannelHandlerContext findContextInbound() { AbstractChannelHandlerContext ctx = this; do { ctx = ctx.next; } while (!ctx.inbound); return ctx; }
That is, it's pointing to the next ChannelHandlerContext object repeatedly.