Netty 이벤트 핸들러 실행 순서
Netty를 사용하다보면 채널 파이프라인에 여러 이벤트 핸들러를 추가하기 마련이다.
그러다보니 순서가 중요할 때가 있다.
- 클라에서 보낸 데이터 중에 헤더를 파싱하고,
- 헤더에 따라 바디를 파싱하고,
- 바디를 토대로 뭔가를 또 처리해야하고…
이런 식으로 N 개의 이벤트 핸들러를 붙여야하고, 순서가 중요하다보니 어떤 순서대로 실행되는지가 궁금해졌다.
Inbound Event Handler
1 | class ExampleHandler1 : ChannelInboundHandlerAdapter() { |
그리고 채널 파이프라인에 순서대로 등록해주자.1
2
3
4
5
6
7
8
9
10// ...
object : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) {
ch.pipeline()
.addLast(ExampleHandler1())
.addLast(ExampleHandler2())
.addLast(ExampleHandler3())
}
}
// ...
Outbound Event Handler
Outbound Event를 발생시키기 위해서는 Inbound Event Handler에서 Outbound Event를 한 번 발생시켜야하기 때문에 둘을 짬뽕시켜보았다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class InboundHandler1 : ChannelInboundHandlerAdapter() {
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
println("1")
ctx.write(msg)
}
}
class OutboundHandler2 : ChannelOutboundHandlerAdapter() {
override fun write(ctx: ChannelHandlerContext, msg: Any, promise: ChannelPromise) {
println("2")
ctx.write(msg, promise)
}
}
class OutboundHandler3 : ChannelOutboundHandlerAdapter() {
override fun write(ctx: ChannelHandlerContext, msg: Any, promise: ChannelPromise) {
println("3")
ctx.write(msg, promise)
}
}
그리고 채널 파이프라인에 순서대로 등록해보았다.1
2
3
4
5
6
7
8object : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) {
ch.pipeline()
.addLast(InboundHandler1())
.addLast(OutboundHandler2())
.addLast(OutboundHandler3())
}
}
하지만 1만 출력되고, 2와 3은 출력되지 않았다.
답은 Outbound Event는 Top-down 순서로 실행되기 때문이다.
1 | object : ChannelInitializer<Channel>() { |
OutboundHandler2, OutboundHandler3 순서대로 실행돼서 1이 찍힌 후에 2와 3이 찍힌다.
Duplex Event Handler
Inbound/Outbound Event를 모두 핸들링하는 Duplex Event Handler를 추가해서 실행 순서를 살펴보자.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32class InboundHandler1 : ChannelInboundHandlerAdapter() {
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
println("1")
ctx.write(msg)
}
}
class OutboundHandler2 : ChannelOutboundHandlerAdapter() {
override fun write(ctx: ChannelHandlerContext, msg: Any, promise: ChannelPromise) {
println("2")
ctx.write(msg, promise)
}
}
class DuplexHandler3 : ChannelDuplexHandler() {
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
println("3 - read")
ctx.fireChannelRead(msg)
}
override fun write(ctx: ChannelHandlerContext, msg: Any, promise: ChannelPromise) {
println("3 - write")
ctx.write(msg, promise)
}
}
class OutboundHandler4 : ChannelOutboundHandlerAdapter() {
override fun write(ctx: ChannelHandlerContext, msg: Any, promise: ChannelPromise) {
println("4")
ctx.write(msg, promise)
}
}
채널 파이프라인에 추가해주자.1
2
3
4
5
6
7
8
9object : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) {
ch.pipeline()
.addLast(OutboundHandler4())
.addLast(DuplexHandler3())
.addLast(OutboundHandler2())
.addLast(InboundHandler1())
}
}
Inbound Handler는 Bottom-up 순서대로 실행되기 때문에
- 먼저 등록된 DuplexHandler3의
3 - read
출력 - 그 후 등록된 InboundHandler1의
1
출력
Outbound Handler는 Top-down 순서대로 실행되기 때문에
- OutboundHandler2의
2
출력 - DuplexHandler3의
3 - write
출력 - OutboundHandler4의
4
출력