netty时如何切换IO模式的
在学习netty时,会发现netty切换IO模式的方式非常便捷。
如下列代码,基于NIO的模式通过netty构架一个服务端。
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
.addLast(new DemoHandler);
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
如果哪天我们想切换IO模式,想从NIO修改为BIO,仅仅只需要修改两个地方。
- 将NioEventLoopGroup -> OioEventLoopGroup
- 将NioServerSocketChannel修改为OioServerSocketChannel
EventLoopGroup bossGroup = new OioEventLoopGroup();
EventLoopGroup workerGroup = new OioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(OioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
.addLast(new DemoHandler);
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
其他代码不变,底层的IO模式就轻松切换了。通常在jdk上开发,我们写业务逻辑,从BIO切换到NIO,这两种IO模式的编程风格的不同,让我们在切换时很难下手。netty封装了这种复杂性,提供了简易的API,那时怎么做到的呢。
IO模式切换的设计模式(泛型+反射+工厂模式)
bootstrap.channel(XxxServerSocketChannel.class)这行代码意思是指定产生Channel的ChannelFactory。
bootstrap是如何根据传入class动态的生成ChannelFactory的(传入OIO,要初始化OIO的ChannelFactory,传入NIO要生成NIO的ChannelFactory)。
这里看下channel的代码逻辑:
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> {
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
}
这段代码需要关注两个泛型,以及一个类ReflectiveChannelFactory。
AbstractBootstrap在定义的时候用到两个泛型,B代表着的是AbstractBootstrap的子类,是父类在自己的代码范围内,获取到子类class的一种手段。C代表着的时Channel的实际类型,在子类定义时指定。
ReflectiveChannelFactory,如字面意思,是一个基于反射的ChannelFactory。传入的channelClass时希望channelFactory生产出来的对象类型。
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
private final Class<? extends T> clazz;
public ReflectiveChannelFactory(Class<? extends T> clazz) {
if (clazz == null) {
throw new NullPointerException("clazz");
}
this.clazz = clazz;
}
@Override
public T newChannel() {
try {
return clazz.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + clazz, t);
}
}
}
这里通过传入的class,通过反射创建一个新对象。由于前面传入了ChannelClass,可以指定返回值类型为传入的ChannelClass。
优点
需要什么类型的对象工厂,传入对象的class就行。
平时我们应用工厂模式,要产生A对象,需要定义A的工厂AFactory;要产生B对象,需要定义B的工厂BFactory。定义的对象一多,需要创建的工厂也多。
基于反射的工厂,就只需定义一个工厂就能产生想要类型的对象。
写个demo应用
public class ReflectiveFactory<T> {
private Class<T> clazz;
public ReflectiveFactory(Class<T> clazz) {
this.clazz = clazz;
}
public T newInstance() {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("生成对象失败");
}
}
@SuppressWarnings("unchecked")
public static void main(String[] args) {
// 生产水果
ReflectiveFactory<Fruit> fruitFactory = (ReflectiveFactory<Fruit>) new ReflectiveFactory(Fruit.class);
Fruit fruit = fruitFactory.newInstance();
// 生成蔬菜
ReflectiveFactory<Vegetable> vegetableFactory = (ReflectiveFactory<Vegetable>) new ReflectiveFactory(Vegetable.class);
Vegetable vegetable = vegetableFactory.newInstance();
}
}