Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.util.Assert;

Expand All @@ -38,6 +40,7 @@ class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCa

private final Function<ExtensionContext, ApplicationContext> lookup;
private @Nullable ThreadBoundApplicationListenerAdapter listener;
private @Nullable PropagateDelegateFromMainThreadTaskDecorator delegatePropagator;

PublishedEventsParameterResolver() {
this(ctx -> SpringExtension.getApplicationContext(ctx));
Expand Down Expand Up @@ -79,6 +82,9 @@ public PublishedEvents resolveParameter(ParameterContext parameterContext, Exten
if (listener != null) {
listener.registerDelegate(publishedEvents);
}
if (delegatePropagator != null) {
delegatePropagator.publishedEventsListener = publishedEvents;
}

return publishedEvents;
}
Expand Down Expand Up @@ -106,6 +112,12 @@ private void initializeListener(ExtensionContext extensionContext) {

return adapter;
});

delegatePropagator = new PropagateDelegateFromMainThreadTaskDecorator(listener);
ThreadPoolTaskExecutor taskExecutor = context.getBeanProvider(ThreadPoolTaskExecutor.class).getIfAvailable();
if (taskExecutor != null) {
taskExecutor.setTaskDecorator(delegatePropagator);
}
}

/*
Expand Down Expand Up @@ -165,4 +177,31 @@ public void onApplicationEvent(ApplicationEvent event) {
}
}
}

private static final class PropagateDelegateFromMainThreadTaskDecorator implements TaskDecorator {
private final ThreadBoundApplicationListenerAdapter adapter;
@Nullable
private ApplicationListener<ApplicationEvent> publishedEventsListener;

PropagateDelegateFromMainThreadTaskDecorator(ThreadBoundApplicationListenerAdapter adapter) {
this.adapter = adapter;
}

@Override
public Runnable decorate(Runnable task) {
return () -> {
if (publishedEventsListener == null) {
task.run();
return;
}
ApplicationListener<ApplicationEvent> previous = adapter.delegate.get();
try {
adapter.delegate.set(publishedEventsListener);
task.run();
} finally {
adapter.delegate.set(previous);
}
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@
import lombok.RequiredArgsConstructor;

import org.awaitility.Awaitility;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
* Integration tests for {@link PublishedEvents}.
Expand All @@ -38,12 +42,25 @@
@RequiredArgsConstructor
@ExtendWith(PublishedEventsExtension.class)
@SpringBootTest(classes = TestConfiguration.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class PublishedEventsIntegrationTests {

@Autowired ApplicationEventPublisher publisher;
@Autowired AsyncEventListener listener;
@Autowired ThreadPoolTaskExecutor taskExecutor;

@Test // #1513
@Order(1)
void initializeTaskThreadsBeforePublishedEventsAreInitialized() {
for (int i = 0; i < 20; ++i) {
taskExecutor.execute(() -> {
// no op
});
}
}

@Test // #116
@Order(2)
void capturesEventsTriggeredByAsyncEventListeners(PublishedEvents events) {

assertThatNoException().isThrownBy(() -> {
Expand Down