适配器模式是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
适配器模式一般用于屏蔽业务逻辑与第三方服务的交互,或者是新老接口之间的差异。
在Dubbo中,所有的数据都是通过Netty来负责传输的,然后这就涉及了消息编解码的问题。
所以,首先它有一个编解码器的接口,负责编码和解码。
- @SPI
- public interface Codec2 {
- @Adaptive({Constants.CODEC_KEY})
- void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException;
-
- @Adaptive({Constants.CODEC_KEY})
- Object decode(Channel channel, ChannelBuffer buffer) throws IOException;
-
- enum DecodeResult {
- NEED_MORE_INPUT, SKIP_SOME_INPUT
- }
- }
然后,有几个实现类,比如DubboCountCodec、DubboCodec、ExchangeCodec等。
但是,当打开这些类的时候,就会发现,他们都是Dubbo中普通的类,只是实现了Codec2接口,其实不能直接作用于Netty编解码。
这是因为,Netty编解码需要实现ChannelHandler接口,这样才会被声明成Netty的处理组件。比如像MessageToByteEncoder、ByteToMessageDecoder那样。
鉴于此,Dubbo搞了一个适配器,专门来适配编解码器接口。
- final public class NettyCodecAdapter {
- private final ChannelHandler encoder = new InternalEncoder();
- private final ChannelHandler decoder = new InternalDecoder();
- private final Codec2 codec;
- private final URL url;
- private final org.apache.dubbo.remoting.ChannelHandler handler;
-
- public NettyCodecAdapter(Codec2 codec, URL url, org.apache.dubbo.remoting.ChannelHandler handler) {
- this.codec = codec;
- this.url = url;
- this.handler = handler;
- }
- public ChannelHandler getEncoder() {
- return encoder;
- }
- public ChannelHandler getDecoder() {
- return decoder;
- }
-
- private class InternalEncoder extends MessageToByteEncoder {
- @Override
- protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
- org.apache.dubbo.remoting.buffer.ChannelBuffer buffer = new NettyBackedChannelBuffer(out);
- Channel ch = ctx.channel();
- NettyChannel channel = NettyChannel.getOrAddChannel(ch, url, handler);
- codec.encode(channel, buffer, msg);
- }
- }
- private class InternalDecoder extends ByteToMessageDecoder {
- @Override
- protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out) throws Exception {
- ChannelBuffer message = new NettyBackedChannelBuffer(input);
- NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
- //解码对象
- codec.decode(channel, message);
- //省略部分代码...
- }
- }
- }
上面的代码中,可以看到,NettyCodecAdapter类适配的是Codec2接口,通过构造函数传递实现类,然后定义了内部的编码器实现和解码器实现,同时它们都是ChannelHandler。
这样的话,在内部类里面的编码和解码逻辑,真正调用的还是Codec2接口。
最后再来看看,该适配器的调用方式。
- //通过SPI方式获取编解码器的实现类,比如这里是DubboCountCodec
- Codec2 codec = ExtensionLoader.getExtensionLoader(Codec2.class).getExtension("dubbo");
- URL url = new URL("dubbo", "localhost", 22226);
- //创建适配器
- NettyCodecAdapter adapter = new NettyCodecAdapter(codec, url, NettyClient.this);
- //向ChannelPipeline中添加编解码处理器
- ch.pipeline()
- .addLast("decoder", adapter.getDecoder())
- .addLast("encoder", adapter.getEncoder())
以上,就是Dubbo中关于编解码器对于适配器模式的应用。