欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 【Netty】netty中都是用了哪些设计模式

【Netty】netty中都是用了哪些设计模式

2025/5/16 9:51:43 来源:https://blog.csdn.net/jia970426/article/details/141904899  浏览:    关键词:【Netty】netty中都是用了哪些设计模式

对于工程师来说,掌握并理解运用设计模式,是非常重要的,但是除了学习基本的概念之外,需要结合优秀的中间件、框架源码学习其中的优秀软件设计,这样才能以不变应万变。

单例模式

单例模式解决的对象的唯一性,一般来说就是构造方法私有化、然后提供一个静态的方法获取实例。
在netty中,select用于处理CONTINUE、SELECT、BUSY_WAIT 三种策略,通过DefaultSelectStrategy实现饿汉式。

final class DefaultSelectStrategy implements SelectStrategy {static final SelectStrategy INSTANCE = new DefaultSelectStrategy();private DefaultSelectStrategy() { }@Overridepublic int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {// 是否有任务 ,有就不阻塞  ,否则就阻塞return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;}
}

工厂方法模式

工厂方法解决的是批量同类型的对象的创建过程。
对于netty来说,在客户端和服务端启动过程中,会设置对应的channel类型,如果直接写死,必然不够优雅,所以可以反射方式,通过Class对象,进行不同类的实例化。具体操作就是如下两个方法,先获取Class的构造器,然后在进行newStance实例化。

虽然反射有一定的性能损失,但是这种方式可以有效减少工厂类的数量。所以损失一定的性能,还是非常值得的,但是如果对于性能比较敏感的业务场景,就需要具体问题具体思考了。也就是trade-off,你看不仅仅在分布式系统设计过程中有trade-off,在软件设计,编码层面也需要多思考具体的业务情况。

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {private final Constructor<? extends T> constructor;public ReflectiveChannelFactory(Class<? extends T> clazz) {ObjectUtil.checkNotNull(clazz, "clazz");try {// 通过Class对象 获取构造参数// 等待后续的利用反射进行创建对象this.constructor = clazz.getConstructor();} catch (NoSuchMethodException e) {throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +" does not have a public non-arg constructor", e);}}@Overridepublic T newChannel() {try {// 对象实例化return constructor.newInstance();} catch (Throwable t) {throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);}}@Overridepublic String toString() {return StringUtil.simpleClassName(ReflectiveChannelFactory.class) +'(' + StringUtil.simpleClassName(constructor.getDeclaringClass()) + ".class)";}
}

责任链模式

责任链在netty中就非常熟悉了,那就是通过双向链表构建的channelPipeline,具体

    protected DefaultChannelPipeline(Channel channel) {tail = new TailContext(this); // 构建尾部节点head = new HeadContext(this); // 构建头节点head.next = tail; // 首尾相连接tail.prev = head;}

在这里插入图片描述

这里可以看到将添加到handler封装成了一个HandlerContext,为什么要这么做?

ChannelHandlerContext提供了时间处理的时间传播机制,如果在handler中,那么就需要在所有的用户自定义handler中都是实现,显然成本是比较高的。这种方式就只需要实现一次,直接复用就可以。

    private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);}

建造者模式

构建者模式解决的构建一个复杂对象的过程,而netty服务端和客户端的BootStrap就是这个过程。
比较优雅的是,通过链式编程 可以非常随意的设置对应的配置。

        EventLoopGroup bossGrpup = new NioEventLoopGroup(1);EventLoopGroup wrokerGrpup = new NioEventLoopGroup();ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGrpup,wrokerGrpup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new LoggingHandler());}});ChannelFuture f = bootstrap.bind(8888).sync();f.channel().closeFuture().sync();

策略模式

策略模式解决的是针对同一个问题 不同算法的处理,策略之间可以互相替换,比如通过手机号 或者 邮箱可以查询用户的个人信息,就需要根据入参的不同 动态选择不同的策略。当有新增的不同的策略时,因为将稳定层进行了封装起来,只需要调整变化层,对于核心代码的修改很少,也容易减少bug。

netty在选择线程的时候,根据当前的是否是2的次幂,选择不同的策略方式,如果是的2的次幂,选择使用 &,否则选择 % ,&的性能相对来说比% 更高。

public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();private DefaultEventExecutorChooserFactory() { }@Overridepublic EventExecutorChooser newChooser(EventExecutor[] executors) {if (isPowerOfTwo(executors.length)) {return new PowerOfTwoEventExecutorChooser(executors);} else {return new GenericEventExecutorChooser(executors);}}private static boolean isPowerOfTwo(int val) {return (val & -val) == val;}private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {private final AtomicInteger idx = new AtomicInteger();private final EventExecutor[] executors;PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {this.executors = executors;}@Overridepublic EventExecutor next() {return executors[idx.getAndIncrement() & executors.length - 1];}}private static final class GenericEventExecutorChooser implements EventExecutorChooser {private final AtomicLong idx = new AtomicLong();private final EventExecutor[] executors;GenericEventExecutorChooser(EventExecutor[] executors) {this.executors = executors;}@Overridepublic EventExecutor next() {return executors[(int) Math.abs(idx.getAndIncrement() % executors.length)];}}
}

装饰者模式

装饰者模式的目的解决的为目标类增加功能,比如原来男人,但是可以增加男人会化妆的功能,
在netty中就是实现了对ByteBuf侧重于在原来功能的拓展,增加日志,事务处理等。而装饰者侧重于为目标类增加新的功能。

代理模式和装饰者模式的区别,前者针对目标类是拓展功能

final class UnreleasableByteBuf extends WrappedByteBuf {private SwappedByteBuf swappedBuf;UnreleasableByteBuf(ByteBuf buf) {super(buf instanceof UnreleasableByteBuf ? buf.unwrap() : buf);}

模板方法模式

模板解决的是拓展问题,通过将一个稳定点,抽象到核心流程,然后交给不同的子类来实现。对于这个实现,在Spring框架中提供了Bean生命周期的拓展点,以实现不同的逻辑。

而在netty中,在初始化的时候,因为客户端和服务端都继承同一个父类,那么将init就可以不同实现。
在这里插入图片描述

    abstract void init(Channel channel) throws Exception;

在这里插入图片描述

在这里插入图片描述

总结

设计模式的学习,不仅仅在于了解各个模式后的使用,而要了解设计背后的目的解决的问题,然后在遇到实际问题的时候,思考能不能使用对应的模式解决。而不是蛮干,炫技使用。另外掌握设计模式最有效的方式就是看各种优秀的中间件、框架源码,netty是一个很好的资源,Spring、MyBatis、JDK等都可以去翻看。

当然看源码的时候,一定要带着目的去读,不然就可能迷失在浩瀚的代码细节中。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词