Java开源框架中的设计模式以及应用场景

五、适配器模式

适配器模式是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

适配器模式一般用于屏蔽业务逻辑与第三方服务的交互,或者是新老接口之间的差异。

我们知道,在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 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中关于编解码器对于适配器模式的应用。

六、责任链模式

责任链模式为请求创建了一个接收者对象的链。允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。

我们来看一个Netty中的例子。我们知道,在Netty中服务端处理消息,就要添加一个或多个ChannelHandler。那么,承载这些ChannelHandler的就是ChannelPipeline,它的实现过程就体现了责任链模式的应用。

ServerBootstrap serverBootstrap = new ServerBootstrap();

serverBootstrap.childHandler(new ChannelInitializer() {

protected void initChannel(NioSocketChannel channel) {

channel.pipeline()

.addLast(new ChannelHandler1())

.addLast(new ChannelHandler2())

.addLast(new ChannelHandler3());

}

});

需要知道的是,在Netty整个框架里面,一条连接对应着一个Channel,每一个新创建的Channel都将会被分配一个新的ChannelPipeline。

ChannelPipeline里面保存的是ChannelHandlerContext对象,它是Channel相关的上下文对象,里面包着我们定义的处理器ChannelHandler。

根据事件的起源,IO事件将会被ChannelInboundHandler或者ChannelOutboundHandler处理。随后,通过调用ChannelHandlerContext实现,它将被转发给同一超类型的下一个ChannelHandler。

1、ChannelHandler

首先,我们来看责任处理器接口,Netty中的ChannelHandler,它充当了所有处理入站和出站数据的应用程序逻辑的容器。

public interface ChannelHandler {

//当把 ChannelHandler 添加到 ChannelPipeline 中时被调用

void handlerAdded(ChannelHandlerContext ctx) throws Exception;

//当从 ChannelPipeline 中移除 ChannelHandler 时被调用

void handlerRemoved(ChannelHandlerContext ctx) throws Exception;

//当处理过程中在 ChannelPipeline 中有错误产生时被调用

void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

}

然后Netty定义了下面两个重要的ChannelHandler子接口:

1、ChannelInboundHandler,处理入站数据以及各种状态变化;

public interface ChannelInboundHandler extends ChannelHandler {

//当 Channel 已经注册到它的 EventLoop 并且能够处理 I/O 时被调用

void channelRegistered(ChannelHandlerContext ctx) throws Except

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值