Java读源码之Netty深入剖析2-1-1 netty的设计模式
如果要阅读源码,首先就要学会基本的设计模式。
设计模式是前人总结出来的软件设计方法,有利于使代码更加简洁优雅。
了解了netty的设计模式,再去看源码,会有一种焕然大悟的感觉。
一、单例模式
单例模式是最常见的设计模式:
1、忽略反射的影响,全局只有一个实例
2、有可能会出现延迟创建实例对象,要使用的时候才创建3、这种设计模式能够避免线程安全问题
netty设计模式-单例模式
单例模式是最常见的设计模式:
1、忽略反射的影响,全局只有一个实例
2、有可能会出现延迟创建实例对象,要使用的时候才创建
3、这种设计模式能够避免线程安全问题
最常见的单例模式实现方法:
懒汉模式(单例对象 volatile + 双重检测机制 -> 禁止指令重排)
public class SingletonExample5 {
// 私有构造函数
private SingletonExample5() {
}
// 1、memory = allocate() 分配对象的内存空间
// 2、ctorInstance() 初始化对象
// 3、instance = memory 设置instance指向刚分配的内存
// 单例对象 volatile + 双重检测机制 -> 禁止指令重排
private volatile static SingletonExample5 instance = null;
// 静态的工厂方法
public static SingletonExample5 getInstance() {
if (instance == null) { // 双重检测机制 // B
synchronized (SingletonExample5.class) { // 同步锁
if (instance == null) {
instance = new SingletonExample5(); // A - 3
}
}
}
return instance;
}
用私有构造函数实现全局一个对象实例,用静态工厂方法实现延迟加载,用各种锁的机制,实现线程安全。
netty里面的单例模式有MqttEncoder和ReadTimeoutException,代码如下:
@ChannelHandler.Sharable
public final class MqttEncoder extends MessageToMessageEncoder<MqttMessage> {
public static final MqttEncoder INSTANCE = new MqttEncoder();
private MqttEncoder() { }
public final class ReadTimeoutException extends TimeoutException {
private static final long serialVersionUID = 169287984113283421L;
public static final ReadTimeoutException INSTANCE = new ReadTimeoutException();
private ReadTimeoutException() { }
}
他们都是使用私有构造函数实现全局单个对象实例,用public static final实现延迟加载和线程安全。
二、策略模式
1、封装一系列可替换的算法家族
2、支持动态选择某一个策略
netty设计模式-策略模式
策略模式的特点大致如下:
1、封装一系列可替换的算法家族
2、支持动态选择某一个策略
常见的策略模式实现方式
/**
* @see DefaultEventExecutorChooserFactory#newChooser(EventExecutor[])
*/
public class Strategy {
private Cache cacheMemory = new CacheMemoryImpl();
private Cache cacheRedis = new CacheRedisImpl();
public interface Cache {
boolean add(String key, Object object);
}
public class CacheMemoryImpl implements Cache {
@Override
public boolean add(String key, Object object) {
// 保存到map
return false;
}
}
public class CacheRedisImpl implements Cache {
@Override
public boolean add(String key, Object object) {
// 保存到redis
return false;
}
}
public Cache getCache(String key) {
if (key.length() < 10) {
return cacheRedis;
}
return cacheMemory;
}
}
在netty的DefaultEventExecutorChooserFactory 的里面,就是如此实现策略模式的:
@UnstableApi
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();
private DefaultEventExecutorChooserFactory() { }
@SuppressWarnings("unchecked")
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTowEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
private static final class PowerOfTowEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
PowerOfTowEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
GenericEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
}
}
三、装饰器模式
装饰器模式被大量地使用在各种框架的源码里面,真正学会了对看源码和设计软件受益匪浅。
1、装饰者和被