N
N
NEO not chosen2019-08-21 14:51:31
Java
NEO not chosen, 2019-08-21 14:51:31

Spring Custom Events | why is ApplicationListener working but @EventListener not working?

There is this abstract code:

Master code

package com.test.testTest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import javax.annotation.PostConstruct;

@SpringBootApplication
public class TestTestApplication {

  public static void main(String[] args) {
    SpringApplication.run(TestTestApplication.class, args);
  }

  @Autowired
  MyService1 service1;

  @PostConstruct
  void init() {
    service1.publish1();
  }
}


My custom events

package com.test.testTest;

import org.springframework.context.ApplicationEvent;

public class MyEvent1 extends ApplicationEvent {

    public MyEvent1(Object source) {
        super(source);
    }
}

package com.test.testTest;

import org.springframework.context.ApplicationEvent;

public class MyEvent2 extends ApplicationEvent {
    public MyEvent2(Object source) {
        super(source);
    }
}


Event publisher service

package com.test.testTest;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MyService1 {

    @Autowired
    ApplicationEventPublisher publisher;

    public void publish1(){
        log.info("pre publishEvent1");
        publisher.publishEvent(new MyEvent1(this));
        log.info("post publishEvent1");
    }

    public void publish2(){
        log.info("pre publishEvent1");
        publisher.publishEvent(new MyEvent2(this));
        log.info("post publishEvent1");
    }
}


Event listener service

package com.test.testTest;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MyService2 {

    @EventListener
    public void handleMyEvent1(MyEvent1 event) {
        log.info("receive event1 {} ", event);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @EventListener
    public void handleMyEvent2(MyEvent2 event) {
        log.info("receive event2 {} ", event);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}


pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.7.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.test</groupId>
  <artifactId>testTest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>testTest</name>
  <description>Demo project for Spring Boot</description>

  <properties>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>


In the logs I have this

2019-08-21 14:45:07.346 INFO 1236 --- [ main] com.test.testTest.TestTestApplication : Starting TestTestApplication on ws044 with PID 1236 (C:\Users\kurochkin-mv-180808\Documents\dev\java\spring\testTest\target\classes started by kurochkin-mv-180808 in C:\Users\kurochkin-mv-180808\Documents\dev\java\spring\testTest)
2019-08-21 14:45:07.349 INFO 1236 --- [ main] com.test.testTest.TestTestApplication : No active profile set, falling back to default profiles: default
2019-08-21 14:45:07.855 INFO 1236 --- [ main] com.test.testTest.MyService1 : pre publishEvent1
2019-08-21 14:45:07.856 INFO 1236 --- [ main] com.test.testTest.MyService1 : post publishEvent1
2019-08-21 14:45:08.021 INFO 1236 --- [ main] com.test.testTest.TestTestApplication : Started TestTestApplication in 1.009 seconds (JVM running for 1.35)
Process finished with exit code 0

At the same time, if you use the old event listener approach, then everything works fine , can you please explain why this is so? And how to make it work through annotations.
The old approach to listen for events through the interface

@Service
@Slf4j
public class MyService2 implements ApplicationListener<MyEvent1> {

    @Override
    public void onApplicationEvent(MyEvent1 event) {
        log.info("receive event1 {} ", event);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


In the logs with the old approach

2019-08-21 14:48:25.194 INFO 9928 --- [ main] com.test.testTest.TestTestApplication : Starting TestTestApplication on ws044 with PID 9928 (C:\Users\kurochkin-mv-180808\Documents\dev\java\spring\testTest\target\classes started by kurochkin-mv-180808 in C:\Users\kurochkin-mv-180808\Documents\dev\java\spring\testTest)
2019-08-21 14:48:25.198 INFO 9928 --- [ main] com.test.testTest.TestTestApplication : No active profile set, falling back to default profiles: default
2019-08-21 14:48:25.754 INFO 9928 --- [ main] com.test.testTest.MyService1 : pre publishEvent1
2019-08-21 14:48:25.755 INFO 9928 --- [ main] com.test.testTest.MyService2 : receive event1 com.test.testTest.MyEvent1
2019-08-21 14:48:26.757 INFO 9928 --- [ main] com.test.testTest.MyService1 : post publishEvent1
2019-08-21 14:48:26.897 INFO 9928 --- [ main] com.test.testTest.TestTestApplication : Started TestTestApplication in 2.085 seconds (JVM running for 2.421)

I do by mana: https://www.baeldung.com/spring-events#annotation-...

Answer the question

In order to leave comments, you need to log in

2 answer(s)
N
NEO not chosen, 2019-08-22
@NeoIsNotTheOne

In the main code, I changed the starter of the whole movement and began to rob:

@PostConstruct
  void init() {
    service1.publish1();
  }

@EventListener
  public void onContextStart(ContextRefreshedEvent event) {
    service1.publish1();
  }

If someone with more experience can explain why this is, I'd appreciate it, but it's possible the events were published before the listener registrar had time to register our listener, but that's just my guess.

W
willrock, 2021-12-26
@willrock

If my memory serves me right, it @PostConstructfires right after the beans are created, but not yet initialized, but it @EventListener(ContextRefreshedEvent.class)will work at the very end after the beans are initialized (and can even be called several times after the application starts if the context has changed)
Accordingly, in the first In this case, a message can be sent, but the listener for this message has not yet been initialized, so it is not processed.
But this is just a guess.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question