前言:
最近做的项目使用到了Netty,之前对网络编程这块知识比较欠缺,所以就学习了一下,与大家分享一下。建议看本篇前了解下纯Java如何实现NIO以及使用Netty如何实现NIO。
源码解析:
那么我们从哪里开始看呢?分析源码这个入口很是重要。既然分析Client引导类,那么Client Connect Server是最重要的,了解Netty实现NIO,有这么一行代码:
BootStrap client = new BootStrap();
client.connect(ip,port);
那我们就从BootStrap.connect(String inetHost,int port)开始今天的旅程。前方高能~~~~
// BootStrap
public ChannelFuture connect(String inetHost, int inetPort) {
return connect(InetSocketAddress.createUnresolved(inetHost, inetPort));
}
public ChannelFuture connect(InetAddress inetHost, int inetPort) {
return connect(new InetSocketAddress(inetHost, inetPort));
}
public ChannelFuture connect(SocketAddress remoteAddress) {
// 最终调用是该方法
if (remoteAddress == null) {
throw new NullPointerException("remoteAddress");
}
// 参数校验
validate();
// 这个方法很重要了 点进去看下
return doResolveAndConnect(remoteAddress, config.localAddress());
}
private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress,
final SocketAddress localAddress) {
// 该方法是初始化通道,熟悉NIO 都知道Channel这个东西很重要,跟进去看一下
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
/** 以下源码先省略 看下initAndRegister这个方法 **/
//AbstractBootStrap
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// 创建Channel看下如何创建的。点进去发现是个接口。 *1
// 我们在实现NIO时调用了
// BootStrap.channel(NioSocketChannel.class)设置了NIO通道类型
channel = channelFactory.newChannel();
// BootStrap.init;
init(channel);
........
........
}
// BootStrap
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
// 创建了ReflectiveChannelFactory,去构造方法看看 *2
// 其实上面的channelFactory.newChannel();
// 其实调用的是ReflectiveChannelFactory.newChannel() 跟下该方法 *4
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
// ReflectiveChannelFactory
// *3
public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
@Override
public T newChannel() {
try {
// 原来就是简单的反射创建NioSocketChannel *5
// 反射创建是调用了NioSocketChannel无参构造,继续。跳到NioSocketChannel中
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
// NioSocketChannel
public NioSocketChannel() {
// *1
this(DEFAULT_SELECTOR_PROVIDER);
}
public NioSocketChannel(SelectorProvider provider) {
// *2 进入到newSocket方法中
// *4 看完newSocket 需要回来继续追this。
this(newSocket(provider));
}
public class NioSocketChannel extends AbstractNioByteChannel implements
io.netty.channel.socket.SocketChannel {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioSocketChannel.class);
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
// *3
private static SocketChannel newSocket(SelectorProvider provider) {
try {
// 完成通道的创建
/**
* 解惑:都知道Netty是在Java原生基础上封装了一层。
* 原生java实现NIO时,创建通道时,我们用的是SocketChannel.open()看下该方法
* 和当前newSocket方法创建通道是一模一样的(废话)。
*/
return provider.openSocketChannel();
} catch (IOException e) {
throw new ChannelException("Failed to open a socket.", e);
}
}
public NioSocketChannel(SocketChannel socket) {
//*5
this(null, socket);
}
public NioSocketChannel(Channel parent, SocketChannel socket) {
//*6 调用父类AbstractNioByteChannel构造方法
super(parent, socket);
config = new NioSocketChannelConfig(this, socket.socket());
}
// SocketChannel
public static SocketChannel open() throws IOException {
return SelectorProvider.provider().openSocketChannel();
}