욱'S 노트

Tomcat Servlet 3.1 예제 및 동작구조 본문

Programming/Tomcat

Tomcat Servlet 3.1 예제 및 동작구조

devsun 2024. 12. 31. 11:09
반응형

개요

어제는 일단 인텔리J기반에서 서블릿을 실행해보았다. 애초에 목적이 Servlet 3.1이 어떻게 동작하는지 알아보기 위함이므로 아주 간단한 Servlet 3.1 예제를 작성해보자.

 

https://opennote46.tistory.com/257

 

IntelliJ Tomcat 기반 서블릿 테스트

개요Servlet 3.1을 구동원리를 파악해보기 위한 사전 작업 설정에 대한 포스팅이다. 항상 스프링 스타터 혹은 고수준의 프레임워크를 경험하다보니 의외로 세팅에 삽질을 하게 되어서 간단하게 서

opennote46.tistory.com

 

Servlet 3.1 예제 작성

생각보다 Servlet 3.1 예제가 많지 않다. 오라클 공식 사이트에 있는 예제를 기반으로 작성해보았다.

먼저 데이터를 읽을때 사용하는 ReadListener를 구현한다. 각 메소드의 호출 시점은 javadoc에 자세히 설명되어 있지만 간단하게 주석을 달아보았다.

class ReadListenerImpl(val input: ServletInputStream, val res: HttpServletResponse?, val ac: AsyncContext) : ReadListener {
    val queue = LinkedBlockingQueue<String>()

    // 데이터를 읽을 수 있을 때 호출
    override fun onDataAvailable() {
        println("Data is available")

        val sb = StringBuilder()
        var len = -1
        val b = ByteArray(1024)
        while (input.isReady && (input.read(b).also { len = it }) != -1) {
            val data = String(b, 0, len)
            sb.append(data)
        }
        queue.add(sb.toString())
    }

    // 모든 데이터를 읽었을 때 호출
    override fun onAllDataRead() {
        println("Data is all read")

        // now all data are read, set up a WriteListener to write
        val output = res?.outputStream!!
        val writeListener: WriteListener = WriteListenerImpl(output, queue, ac)
        output.setWriteListener(writeListener)
    }

    // 에러가 발생했을 때 호출
    override fun onError(t: Throwable?) {
        ac.complete()
        t?.printStackTrace()!!
    }
}

 

다음은 WriteListener을 작성한다.

class WriteListenerImpl(val output: ServletOutputStream, val queue: LinkedBlockingQueue<String>, val ac: AsyncContext) : WriteListener {
    // 데이터를 쓸 수 있을 때 호출
    override fun onWritePossible() {
        println("Write is possible")

        while (output.isReady && queue.peek() != null) {
            val data = queue.poll()
            output.print(data)
        }

        if (queue.peek() == null) {
            ac.complete()
        }
    }

    //  에러가 발생했을 때 호출
    override fun onError(t: Throwable?) {
        ac.complete();
        t?.printStackTrace()!!
    }
}

 

그리고 Servlet을 하나 구현해보자. 기능은 아주 단순하게 POST 방식으로 전달받은 RequestBody를 그대로 출력하는 것이다.

@WebServlet("/upload", asyncSupported = true)
class UploadServlet : HttpServlet() {
    override fun doPost(req: HttpServletRequest?, resp: HttpServletResponse?) {
        val context: AsyncContext = req?.startAsync()!!

        context.addListener(object : AsyncListener {
            override fun onComplete(event: AsyncEvent?) {
                println("onComplete")
                event?.suppliedRequest
            }

            override fun onTimeout(event: AsyncEvent?) {
                println("onTimeout")
            }

            override fun onError(event: AsyncEvent?) {
                println("onError")
                event?.throwable?.printStackTrace()!!
            }

            override fun onStartAsync(event: AsyncEvent?) {
                println("onStartAsync")
            }
        })

        val input = req.inputStream
        val readListener: ReadListener = ReadListenerImpl(input, resp, context)
        input.setReadListener(readListener)
    }
}

 

테스트

CURL이나 PostMan과 같은 툴을 이용하면 응답이 제대로 돌아오는 것을 알 수 있다. 요청 주소는 http://localhost:8080/{contextPath}/upload 형식이다.

curl --location 'http://localhost:8080/Gradle___com_kakao___sample_1_0_SNAPSHOT_war__exploded_/upload' \
--header 'Content-Type: text/plain' \
--data 'Hello World'

 

동작 구조

Poller가 이벤트를 전달하고 소켓에서 OPEN_READ 이벤트가 발생하면 Request의 ReadListener의 DataAvailable을 수행한다. 만약 읽기가 완료되면 OnDataAllRead() 호출한다. 이후 OPEN_WRITE 이벤트가 발생하면 Response의 WriterListener의 onWritePossible 연산이 수행되며, response에 쓰기 연산을 수행한다. 기존 서블릿은 읽기가 완료될 때 까지 블럭킹이 되었다면 서블릿 3.1에서는 논블럭킹으로 읽기 쓰기 연산이 수행된다.

 

 

출처 : https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/HTML5andServlet31/HTML5andServlet%203.1.html

 

Java EE 7: Using Non-blocking I/O in Servlet 3.1

In this section, you develop a servlet, UploadServlet, which reads and writes the contents of a file with the non-blocking I/O Servlet 3.1 API. The servlet processes the HTTP POST request made by the client asynchronously. The servlet performs the followin

www.oracle.com

 

 

 

 

반응형