Close

Spring MVC - Listening to HTTP request as events

[Last Updated: Mar 23, 2026]

In Spring web application, a bean can register RequestHandledEvent to get notifications that an HTTP request has been serviced. This event is published after the request is complete. Let's see how to do that with example.

RequestHandledEvent Example

package com.logicbig.example;

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.RequestHandledEvent;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

@Component
public class MyBean {
    private AtomicLong counter = new AtomicLong();

    @EventListener
    public void handleEvent (RequestHandledEvent e) {
        System.out.println("-- RequestHandledEvent --");
        System.out.println(e);
        counter.incrementAndGet();
    }

    public long getCount() {
        return counter.get();
    }
}
package com.logicbig.example;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyWebController {

    @RequestMapping("/test")
    @ResponseBody
    public String handle() {
        System.out.println("-- Controller --");
        System.out.println("test handler");
        return "test response from /test";
    }

    @RequestMapping("/test2")
    @ResponseBody
    public String handle2() {
        System.out.println("-- Controller --");
        System.out.println("test2 handler");
        return "test response from /test2";
    }
}

Running Example

To try examples, run embedded Jetty (configured in pom.xml of example project below):

mvn jetty:run

Access following URL in your browser:
http://localhost:8080/test
http://localhost:8080/test2

Output on server console:

[INFO] Started Jetty Server
-- Controller --
test handler
-- RequestHandledEvent --
ServletRequestHandledEvent: url=[/test]; client=[[0:0:0:0:0:0:0:1]]; method=[GET]; servlet=[dispatcher]; session=[null]; user=[null]; time=[51ms]; status=[OK]
Mar 23, 2026 3:50:03 PM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/favicon.ico] in DispatcherServlet with name 'dispatcher'
-- RequestHandledEvent --
ServletRequestHandledEvent: url=[/favicon.ico]; client=[[0:0:0:0:0:0:0:1]]; method=[GET]; servlet=[dispatcher]; session=[null]; user=[null]; time=[1ms]; status=[OK]
-- Controller --
test2 handler
-- RequestHandledEvent --
ServletRequestHandledEvent: url=[/test2]; client=[[0:0:0:0:0:0:0:1]]; method=[GET]; servlet=[dispatcher]; session=[null]; user=[null]; time=[1ms]; status=[OK]

In above output, we see Servlet Request Handled Event, which is a Servlet-specific subclass of RequestHandledEvent. In portlet environment, Spring framework uses another subclass; PortletRequestHandledEvent.

Unit Test

package com.logicbig.example;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.web.context.WebApplicationContext;

import static org.assertj.core.api.Assertions.assertThat;

@SpringJUnitWebConfig(classes = MyWebConfig.class)
public class RequestHandledMvcTest {

    @Autowired
    private WebApplicationContext wac;

    @Autowired
    private MyBean myBean;

    private MockMvcTester mockMvc;

    @BeforeEach
    void setup() {
        this.mockMvc = MockMvcTester.from(this.wac);
    }

    @Test
    void test1() {
        long initialCount = myBean.getCount();

        assertThat(mockMvc.get().uri("/test"))
                .hasStatusOk();

        assertThat(myBean.getCount())
                .isEqualTo(initialCount + 1);
    }

    @Test
    void test2() {
        long initialCount = myBean.getCount();

        assertThat(mockMvc.get().uri("/test2"))
                .hasStatusOk();

        assertThat(myBean.getCount())
                .isEqualTo(initialCount + 1);
    }
}
mvn clean test

Output

$ mvn clean test
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for com.logicbig.example:request-handled-event:jar:1.0-SNAPSHOT
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-war-plugin is missing. @ line 37, column 21
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
[INFO]
[INFO] -------------< com.logicbig.example:request-handled-event >-------------
[INFO] Building request-handled-event 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ request-handled-event ---
[INFO] Deleting D:\example-projects\spring-mvc\request-handled-event\target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ request-handled-event ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\request-handled-event\src\main\resources
[INFO]
[INFO] --- compiler:3.3:compile (default-compile) @ request-handled-event ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 4 source files to D:\example-projects\spring-mvc\request-handled-event\target\classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ request-handled-event ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\request-handled-event\src\test\resources
[INFO]
[INFO] --- compiler:3.3:testCompile (default-testCompile) @ request-handled-event ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to D:\example-projects\spring-mvc\request-handled-event\target\test-classes
[INFO]
[INFO] --- surefire:3.2.5:test (default-test) @ request-handled-event ---
[INFO] Using auto detected provider org.apache.maven.surefire.junit4.JUnit4Provider
[WARNING] file.encoding cannot be set as system property, use <argLine>-Dfile.encoding=...</argLine> instead
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.logicbig.example.RequestHandledMvcTest
-- Controller --
test handler
-- RequestHandledEvent --
ServletRequestHandledEvent: url=[/test]; client=[127.0.0.1]; method=[GET]; servlet=[]; session=[null]; user=[null]; time=[11ms]; status=[OK]
-- Controller --
test2 handler
-- RequestHandledEvent --
ServletRequestHandledEvent: url=[/test2]; client=[127.0.0.1]; method=[GET]; servlet=[]; session=[null]; user=[null]; time=[1ms]; status=[OK]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.534 s -- in com.logicbig.example.RequestHandledMvcTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.516 s
[INFO] Finished at: 2026-03-23T15:44:46+08:00
[INFO] ------------------------------------------------------------------------

Example Project

Dependencies and Technologies Used:

  • spring-webmvc 7.0.6 (Spring Web MVC)
     Version Compatibility: 4.2.0.RELEASE - 7.0.6Version List
    ×

    Version compatibilities of spring-webmvc with this example:

      javax.servlet-api:3.x
    • 4.2.0.RELEASE
    • 4.2.1.RELEASE
    • 4.2.2.RELEASE
    • 4.2.3.RELEASE
    • 4.2.4.RELEASE
    • 4.2.5.RELEASE
    • 4.2.6.RELEASE
    • 4.2.7.RELEASE
    • 4.2.8.RELEASE
    • 4.2.9.RELEASE
    • 4.3.0.RELEASE
    • 4.3.1.RELEASE
    • 4.3.2.RELEASE
    • 4.3.3.RELEASE
    • 4.3.4.RELEASE
    • 4.3.5.RELEASE
    • 4.3.6.RELEASE
    • 4.3.7.RELEASE
    • 4.3.8.RELEASE
    • 4.3.9.RELEASE
    • 4.3.10.RELEASE
    • 4.3.11.RELEASE
    • 4.3.12.RELEASE
    • 4.3.13.RELEASE
    • 4.3.14.RELEASE
    • 4.3.15.RELEASE
    • 4.3.16.RELEASE
    • 4.3.17.RELEASE
    • 4.3.18.RELEASE
    • 4.3.19.RELEASE
    • 4.3.20.RELEASE
    • 4.3.21.RELEASE
    • 4.3.22.RELEASE
    • 4.3.23.RELEASE
    • 4.3.24.RELEASE
    • 4.3.25.RELEASE
    • 4.3.26.RELEASE
    • 4.3.27.RELEASE
    • 4.3.28.RELEASE
    • 4.3.29.RELEASE
    • 4.3.30.RELEASE
    • 5.0.0.RELEASE
    • 5.0.1.RELEASE
    • 5.0.2.RELEASE
    • 5.0.3.RELEASE
    • 5.0.4.RELEASE
    • 5.0.5.RELEASE
    • 5.0.6.RELEASE
    • 5.0.7.RELEASE
    • 5.0.8.RELEASE
    • 5.0.9.RELEASE
    • 5.0.10.RELEASE
    • 5.0.11.RELEASE
    • 5.0.12.RELEASE
    • 5.0.13.RELEASE
    • 5.0.14.RELEASE
    • 5.0.15.RELEASE
    • 5.0.16.RELEASE
    • 5.0.17.RELEASE
    • 5.0.18.RELEASE
    • 5.0.19.RELEASE
    • 5.0.20.RELEASE
    • 5.1.0.RELEASE
    • 5.1.1.RELEASE
    • 5.1.2.RELEASE
    • 5.1.3.RELEASE
    • 5.1.4.RELEASE
    • 5.1.5.RELEASE
    • 5.1.6.RELEASE
    • 5.1.7.RELEASE
    • 5.1.8.RELEASE
    • 5.1.9.RELEASE
    • 5.1.10.RELEASE
    • 5.1.11.RELEASE
    • 5.1.12.RELEASE
    • 5.1.13.RELEASE
    • 5.1.14.RELEASE
    • 5.1.15.RELEASE
    • 5.1.16.RELEASE
    • 5.1.17.RELEASE
    • 5.1.18.RELEASE
    • 5.1.19.RELEASE
    • 5.1.20.RELEASE
    • 5.2.0.RELEASE
    • 5.2.1.RELEASE
    • 5.2.2.RELEASE
    • 5.2.3.RELEASE
    • 5.2.4.RELEASE
    • 5.2.5.RELEASE
    • 5.2.6.RELEASE
    • 5.2.7.RELEASE
    • 5.2.8.RELEASE
    • 5.2.9.RELEASE
    • 5.2.10.RELEASE
    • 5.2.11.RELEASE
    • 5.2.12.RELEASE
    • 5.2.13.RELEASE
    • 5.2.14.RELEASE
    • 5.2.15.RELEASE
    • 5.2.16.RELEASE
    • 5.2.17.RELEASE
    • 5.2.18.RELEASE
    • 5.2.19.RELEASE
    • 5.2.20.RELEASE
    • 5.2.21.RELEASE
    • 5.2.22.RELEASE
    • 5.2.23.RELEASE
    • 5.2.24.RELEASE
    • 5.2.25.RELEASE
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.3.3
    • 5.3.4
    • javax.servlet-api:4.x
    • 5.3.5
    • 5.3.6
    • 5.3.7
    • 5.3.8
    • 5.3.9
    • 5.3.10
    • 5.3.11
    • 5.3.12
    • 5.3.13
    • 5.3.14
    • 5.3.15
    • 5.3.16
    • 5.3.17
    • 5.3.18
    • 5.3.19
    • 5.3.20
    • 5.3.21
    • 5.3.22
    • 5.3.23
    • 5.3.24
    • 5.3.25
    • 5.3.26
    • 5.3.27
    • 5.3.28
    • 5.3.29
    • 5.3.30
    • 5.3.31
    • 5.3.32
    • 5.3.33
    • 5.3.34
    • 5.3.35
    • 5.3.36
    • 5.3.37
    • 5.3.38
    • 5.3.39
    • javax.* -> jakarta.*
      jakarta.servlet-api:6.x
      Java 17 min
    • 6.0.0
    • 6.0.1
    • 6.0.2
    • 6.0.3
    • 6.0.4
    • 6.0.5
    • 6.0.6
    • 6.0.7
    • 6.0.8
    • 6.0.9
    • 6.0.10
    • 6.0.11
    • 6.0.12
    • 6.0.13
    • 6.0.14
    • 6.0.15
    • 6.0.16
    • 6.0.17
    • 6.0.18
    • 6.0.19
    • 6.0.20
    • 6.0.21
    • 6.0.22
    • 6.0.23
    • 6.1.0
    • 6.1.1
    • 6.1.2
    • 6.1.3
    • 6.1.4
    • 6.1.5
    • 6.1.6
    • 6.1.7
    • 6.1.8
    • 6.1.9
    • 6.1.10
    • 6.1.11
    • 6.1.12
    • 6.1.13
    • 6.1.14
    • 6.1.15
    • 6.1.16
    • 6.1.17
    • 6.1.18
    • 6.1.19
    • 6.1.20
    • 6.1.21
    • 6.2.0
    • 6.2.1
    • 6.2.2
    • 6.2.3
    • 6.2.4
    • 6.2.5
    • 6.2.6
    • 6.2.7
    • 6.2.8
    • 6.2.9
    • 6.2.10
    • 6.2.11
    • 6.2.12
    • 6.2.13
    • 6.2.14
    • 6.2.15
    • 6.2.16
    • 6.2.17
    • 7.0.0
    • 7.0.1
    • 7.0.2
    • 7.0.3
    • 7.0.4
    • 7.0.5
    • 7.0.6

    Versions in green have been tested.

  • jakarta.servlet-api 6.1.0 (Jakarta Servlet API documentation)
  • spring-test 7.0.6 (Spring TestContext Framework)
  • junit-jupiter-engine 6.0.3 (Module "junit-jupiter-engine" of JUnit)
  • assertj-core 3.26.3 (Rich and fluent assertions for testing in Java)
  • JDK 25
  • Maven 3.9.11

Spring MVC - RequestHandledEvent Example Select All Download
  • request-handled-event
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • MyBean.java
        • test
          • java
            • com
              • logicbig
                • example

    See Also

    Join