Pertanyaan Kirim pesan RabbitMQ di Spring Application shutdown


Saya memiliki layanan monitor yang mengirim pesan ke rabbitMQ pada startup aplikasi, aplikasi shutdown dan setiap menit (centang).

Acara startup dan tick bekerja dengan baik. Ketika kelas awalnya ditulis acara shutdown juga berhasil.

Saya menggunakan spring-boot-starter-amqp 1.3.3.RELEASE

Acara itu dipecat di destroy metode dari DisposableBean antarmuka.

Saya juga mencoba menerapkan ApplicationListener<ContextClosedEvent> antarmuka dan Lifecycle antarmuka

Kedua metode di atas mengembalikan:

java.lang.IllegalStateException: ApplicationContext ditutup dan   ConnectionFactory tidak dapat lagi membuat koneksi.

Saya perhatikan ada perbaikan bug https://jira.spring.io/browse/AMQP-536 yang menyarankan Lifecycle antarmuka.

Bagaimana saya memastikan pesan acara penutupan saya dikirim sebelum koneksi RabbitMQ ditutup?

EDIT: Info lebih lanjut dan Kode Terbaru

Aplikasi ini memiliki beberapa pabrik koneksi ke server yang berbeda. Layanan Monitor berpindah ke server RabbitMQ melalui monitorRabbitTemplate.

Masalahnya tampaknya menjadi monitorRabbitTemplate Pabrik koneksi mendapat event Lifecycle / Shutdown / Dispose sebelum MonitorService.

Kode terbaru (menggunakan Lifecycle dari pada ApplicationListener<ContextClosedEvent>  dan DisposableBean):

@Component
public class MonitorServiceImpl implements  MonitorService , Lifecycle {
    private static final Logger LOGGER = LoggerFactory.getLogger(MonitorServiceImpl.class);

    private final RabbitTemplate monitorRabbitTemplate;
    private final String queueName;
    private final Gson gson = new Gson();

    @Autowired
    public MonitorServiceImpl(@Qualifier("monitorRabbitTemplate") final RabbitTemplate monitorRabbitTemplate,
                              @Value("${monitor.rabbitmq.queue.name:monitor}") final String queueName) {
        this.monitorRabbitTemplate = monitorRabbitTemplate;
        this.queueName = queueName;
    }

    @Scheduled(fixedDelay = 60000)
    public void tick() {
        try {
            send(new Monitor(Status.INFO, "I am here"));
        } catch (final Exception e) {
            LOGGER.error("FAILED TO SEND TICK EVENT", e);
        }
    }

    @Override
    public void send(final Monitor monitor) {
        try {
            final Message message = MessageBuilder.withBody(gson.toJson(monitor).getBytes())
                .setContentType("application/json").setPriority(0).setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .build();

            monitorRabbitTemplate.send(queueName, message);
        } catch (final Exception e) {
            LOGGER.error("FAILED TO SEND MONITOR EVENT", e);
            LOGGER.error("FAILED TO SEND MONITOR EVENT to {}:{}", monitorRabbitTemplate.getConnectionFactory()
                .getHost(), monitorRabbitTemplate.getConnectionFactory().getPort());

        }

    }

    @Override
    public void start() {
        try {
            send(new Monitor(Status.STARTING, "Application starting up..."));
        } catch (final Exception e) {
            LOGGER.error("FAILED TO SEND STARTUP EVENT", e);
        }
    }

    @Override
    public void stop() {
        try {
            send(new Monitor(Status.TERMINATING, "Application shutdown..."));
        } catch (final Exception e) {
            LOGGER.error("FAILED TO SEND SHUTDOWN EVENT", e);
        }

    }

    @Override
    public boolean isRunning() {
        return true;
    }
}

4
2017-07-18 14:32


asal


Jawaban:


Mungkin Anda bisa berbagi beberapa konfigurasi kode / build? Karena mendengarkan ContextClosedEvent dan implementasi Lifecycle keduanya bekerja untukku.

Inilah aplikasi saya:

@SpringBootApplication
public class SpringRabbitmqDemoApplication {

    @Component
    public static class Whatever implements Lifecycle {
        private final RabbitTemplate template;

        @Autowired
        public Whatever(RabbitTemplate template) {
            this.template = template;
        }

        @EventListener
        public void event(ContextClosedEvent event) throws Exception {
            sendMessage(event.toString());
        }

        private void sendMessage(String message) {
            template.convertAndSend("", "queue", message);
            System.out.println("Sent event " + message);
        }

        @Override
        public void start() {
            sendMessage("start");
        }

        @Override
        public void stop() {
            sendMessage("stop");
        }

        @Override
        public boolean isRunning() {
            return true;
        }
    }

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

Dan file pom.xml saya:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>spring-rabbitmq-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>spring-rabbitmq-demo</name>
    <description>Demo project for Spring Boot RabbitMQ</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </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>

Inilah output yang saya dapatkan:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.3.3.RELEASE)

2016-07-21 17:45:24.984  INFO 77845 --- [           main] c.example.SpringRabbitmqDemoApplication  : Starting SpringRabbitmqDemoApplication on mmilivojevic-hal9000 with PID 77845 (started by mmilivojevic in /Volumes/Macintosh HD/springrabbitmqdemo)
2016-07-21 17:45:24.990  INFO 77845 --- [           main] c.example.SpringRabbitmqDemoApplication  : No active profile set, falling back to default profiles: default
2016-07-21 17:45:25.092  INFO 77845 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@27d415d9: startup date [Thu Jul 21 17:45:25 CEST 2016]; root of context hierarchy
2016-07-21 17:45:26.746  INFO 77845 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.amqp.rabbit.annotation.RabbitBootstrapConfiguration' of type [class org.springframework.amqp.rabbit.annotation.RabbitBootstrapConfiguration$$EnhancerBySpringCGLIB$$2cf55fc7] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2016-07-21 17:45:27.620  INFO 77845 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2016-07-21 17:45:27.636  INFO 77845 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase -2147482648
2016-07-21 17:45:27.637  INFO 77845 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147483647
2016-07-21 17:45:27.661  INFO 77845 --- [           main] c.example.SpringRabbitmqDemoApplication  : Started SpringRabbitmqDemoApplication in 3.456 seconds (JVM running for 4.288)
2016-07-21 17:45:27.662  INFO 77845 --- [       Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@27d415d9: startup date [Thu Jul 21 17:45:25 CEST 2016]; root of context hierarchy
2016-07-21 17:45:27.785  INFO 77845 --- [       Thread-1] o.s.a.r.c.CachingConnectionFactory       : Created new connection: SimpleConnection@7ff53a50 [delegate=amqp://guest@127.0.0.1:5672/]
Sent event org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@27d415d9: startup date [Thu Jul 21 17:45:25 CEST 2016]; root of context hierarchy]
2016-07-21 17:45:27.829  INFO 77845 --- [       Thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147483647
2016-07-21 17:45:27.830  INFO 77845 --- [       Thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 0
Sent event stop
2016-07-21 17:45:27.831  INFO 77845 --- [       Thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase -2147482648
2016-07-21 17:45:27.834  INFO 77845 --- [       Thread-1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

2
2017-07-18 15:07