๊ฐ์
์คํ๋ง์ ์ด๋ฒคํธ ๊ธฐ๋ฅ์ ํ์ฉํ ๋ ํํ AbstractAggregateRoot ํน์ ApplicationEventPublisher๋ฅผ ์ฌ์ฉํ๋ค. ์ด ๊ธ์์๋ ๋ด๋ถ์ ์ผ๋ก ์ด๋ค ๋ฐฉ์์ผ๋ก ๋์ํ๋ฉฐ, ์ด๋ฒคํธ๊ฐ ์ด๋ป๊ฒ ๋ฑ๋ก๋๊ณ ๋ฐํ๋์ด ์ต์ข ์ ์ผ๋ก ์์ ๋๋์ง ์ ์ฒด์ ์ธ ๊ณผ์ ์ ์ ๋ฆฌํด ๋ณธ๋ค.
AbstractAggregateRoot ๋์ ๊ณผ์
AbstractAggregateRoot๋ Spring Data์์ ์ ๊ณตํ๋ ์ถ์ ํด๋์ค๋ก, ๋๋ฉ์ธ ์ด๋ฒคํธ๋ฅผ ๋ณด๋ค ์์ฝ๊ฒ ๋ฑ๋กํ๊ณ ๊ด๋ฆฌํ ์ ์๋๋ก ๋์์ค๋ค. ์ฃผ๋ก DDD์์ ์ํ ๋ณ๊ฒฝ ํ ์ธ๋ถ์ ์๋ฏธ ์๋ ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํ ๋ ์ฌ์ฉ๋๋ค.
์๋ฅผ ๋ค์ด ์ฃผ๋ฌธ์ด ์๋ฃ๋์์ ๋ ๋๋ฉ์ธ ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
@Entity
public class Order extends AbstractAggregateRoot<Order> {
public void complete() {
this.status = OrderStatus.COMPLETED;
// ๋๋ฉ์ธ ์ด๋ฒคํธ ๋ฑ๋ก
registerEvent(new OrderCompletedEvent(this.getId(), /*...*/));
}
}
์ ์ฝ๋์ฒ๋ผ AbstractAggregateRoot.java๋ฅผ ์์ํ ์ํฐํฐ๋ registerEvent() ๋ฉ์๋๋ฅผ ํตํด ๋๋ฉ์ธ ์ด๋ฒคํธ๋ฅผ ๋ด๋ถ์ ์ผ๋ก ๊ด๋ฆฌ๋๋ ๋ฆฌ์คํธ(domainEvents)์ ์ถ๊ฐํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๋ ๊ฒ ๋ฑ๋ก๋ ์ด๋ฒคํธ๋ ๋ค์๊ณผ ๊ฐ์ด Spring Data์ save(), saveAll(), delete(), deleteAll(), deleteAllInBatch(), deleteInBatch() ๋ฑ์ ๋ฉ์๋๊ฐ ํธ์ถ๋ ๋ ์๋์ผ๋ก ์ถ์ถ๋์ด ๋ฐํ๋๋ค.(์ฐธ๊ณ ๋ก deleteById()์ ๊ฒฝ์ฐ์๋ ํธ์ถ๋์ง ์๋๋ค. ์ด์ ๋ #issues/2084๋ฅผ ํ์ธํ์.)
@Transactional
public void completeOrder(Order order) {
order.complete(); // ์ํ ๋ณ๊ฒฝ + registerEvent(...)
orderRepository.save(order); // save() ํธ์ถ → ์ด๋ฒคํธ ๋ฐํ
}
@Transactional
public void cancelOrder(Order order) {
order.cancel(); // cancel() ๋ด๋ถ์์ ์ด๋ฒคํธ ๋ฑ๋ก
orderRepository.delete(order); // delete() ํธ์ถ → ์ด๋ฒคํธ ๋ฐํ
}
์ด๊ฑด ๊ฐ์ธ์ ์ธ ์๊ฐ์ธ๋ฐ ์ฌ์ฉํ๋ฉด์ ์์ฌ์ด ์ ์ ๋๋ฉ์ธ ๋ด๋ถ์์ updateXxx()์ ๊ฐ์ ๋ฉ์๋๋ก ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ๋๋ผ๋ save()๋ delete()๋ฅผ ๋ช ์์ ์ผ๋ก ํธ์ถํ์ง ์์ผ๋ฉด ์ด๋ฒคํธ๊ฐ ๋ฐํ๋์ง ์๋๋ค๋ ์ ์ด๋ค. JPA์ ๋ํฐ ์ฒดํน์ ํตํด ์ํ ๋ณ๊ฒฝ์ ๋ฐ์๋๋๋ผ๋, ์ ๋ฐ์ดํธ ํ์์ ๋ถํ์ํ save()๋ delete() ํธ์ถ์ ์ถ๊ฐํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๊ฒจ ๊ตฌ์กฐ์ ์ผ๋ก ๋ค์ ์ด์ํ๊ฒ ๋๊ปด์ง ์ ์๋ค.
์ฌํผ ์ดํ ๋๋ฉ์ธ ์ด๋ฒคํธ๊ฐ ์ค์ ๋ก ๋ฐํ๋๊ธฐ ์ํด์๋, ์ํฐํฐ์ ์ ์ฅ ๋๋ ์ญ์ ์์ ์ Spring Data ๋ด๋ถ์์ ์ด๋ฒคํธ๋ฅผ ์ถ์ถํ๊ณ ์ด๋ฅผ ApplicationEventPublisher๋ฅผ ํตํด ๋ฐํํ๋ ๊ณผ์ ์ด ํ์ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์ ์ฒด ํ๋ฆ์ ๋ด๋นํ๋ ํต์ฌ ํด๋์ค๊ฐ ๋ฐ๋ก EventPublishingRepositoryProxyPostProcessor.java์ด๋ค.
Spring Data๋ ์ฌ์ฉ์ ์ ์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ๋ด๋ถ์ ์ผ๋ก ํ๋ก์ ๊ฐ์ฒด๋ก ๊ฐ์ธ๋๋ฐ, ์ด ํ๋ก์ ์์ฑ ๊ณผ์ ์์ EventPublishingRepositoryProxyPostProcessor๊ฐ ๊ฐ์ ํ์ฌ ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ฅผ ์ํ ์ธํฐ์ ํฐ๋ฅผ ๋ฑ๋กํ๋ค. ๊ตฌ์ฒด์ ์ผ๋ก๋ ์์ postProcess() ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉฐ, ์ด ์์ ์ EventPublishingMethodInterceptor๊ฐ ํ๋ก์์ ์ถ๊ฐ๋๋ค.
์ดํ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์ repository.save(entity) ๋๋ repository.delete(entity)๊ฐ ํธ์ถ๋๋ฉด, ํด๋น ์ธํฐ์ ํฐ์ invoke() ๋ฉ์๋๊ฐ ์คํ๋๋ค.
์ด invoke() ๋ฉ์๋๋ ๋จผ์ ์ค์ DB ์ ์ฅ ๋ก์ง์ ์ํํ ๋ค, ๋์ ์ํฐํฐ์ @DomainEvents ์ ๋ ธํ ์ด์ ์ด ๋ถ์ ๋ฉ์๋๋ AbstractAggregateRoot์ domainEvents() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ด๋ฒคํธ ๋ชฉ๋ก์ ์ถ์ถํ๋ค. ์ด๋ฒคํธ๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ ํ๋์ฉ ApplicationEventPublisher.publishEvent()๋ฅผ ํตํด ๋ฐํํ๊ณ , ๋ง์ง๋ง์ผ๋ก @AfterDomainEventPublication์ด ๋ถ์ ๋ฉ์๋๋ฅผ ํธ์ถํด ๋ด๋ถ ์ด๋ฒคํธ ๋ฆฌ์คํธ๋ฅผ ์ด๊ธฐํํ๋ค.
๊ฒฐ๊ตญ ๋๋ฉ์ธ ์ด๋ฒคํธ๊ฐ ์ค์ ๋ก ๋ฐํ๋๋ ์์ ์ ์๋ EventPublishingMethod.publishEventsFrom() ๋ฉ์๋์์ ApplicationEventPublisher.publishEvent(...)๊ฐ ํธ์ถ๋ ๋๋ค.
์ด๋ฌํ ํ๋ฆ์ ํตํด ๋๋ฉ์ธ ๊ณ์ธต์์๋ registerEvent()๋ก ์ด๋ฒคํธ๋ง ๋ฑ๋กํ๋ฉด ๋๊ณ , save()๋ delete() ์์ ์ Spring Data๊ฐ ์ด๋ฅผ ์๋์ผ๋ก ์ถ์ถ·๋ฐํํ๋ ๊ตฌ์กฐ๊ฐ ์์ฑ๋๋ค.
์ ๋ด์ฉ๋ค์ ํ์ค๋ก ์์ฝํ๋ฉด AbstractAggregateRoot์์ registerEvent()๋ก ๋ฑ๋ก๋ ์ด๋ฒคํธ๋, save() ๋๋ delete() ๋ฉ์๋๊ฐ ํธ์ถ๋ ์งํ ํธ๋์ญ์ ์์์ ์ฆ์ Spring Data JPA๊ฐ ApplicationEventPublisher๋ฅผ ํตํด ๋ฐํ๋๋ค.
ApplicationEventPublisher ๋์ ๊ณผ์
ApplicationEventPublisher.publishEvent(event)๊ฐ ํธ์ถ๋๋ ์๊ฐ๋ถํฐ, ์ด๋ฒคํธ๋ ์คํ๋ง ์ปจํ ์ด๋ ๋ด๋ถ ํ์ดํ๋ผ์ธ์ ๋ฐ๋ผ ์ ํ๋๋ค. ์ ์ฒด์ ์ธ ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ๋ค.
โ โฏApplicationContext.publishEvent()
ApplicationContext๋ ApplicationEventPublisher๋ฅผ ๊ตฌํํ๋ค. ์ฌ์ฉ์๊ฐ publishEvent(event)๋ฅผ ํธ์ถํ๋ฉด ์ปจํ ์คํธ๊ฐ ๊ฐ์ฅ ๋จผ์ ์ด๋ฒคํธ๋ฅผ ๋ฐ์๋ค์ด๋ ์ง์ ์ ์ด ๋๋ฉฐ, ์ค์ ์ฒ๋ฆฌ๋ ๋ด๋ถ์ ์ผ๋ก AbstractApplicationContext.java์ publishEvent()๋ฅผ ํตํด ์ฒ๋ฆฌ๋๋ค.
โกโฏAbstractApplicationContext.publishEvent()
์ ๋ฌ๋ ๊ฐ์ฒด๊ฐ ApplicationEvent๋ฅผ ์์ํ์ง ์์ ์์ POJO๋ผ๋ฉด, ์ด๋ฅผ PayloadApplicationEvent๋ก ๋ํ ํ๋ค. ๊ทธ ์ด์ ๋ Spring 4.2 ์ด์ ์๋ ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๋ ค๋ฉด ๋ฐ๋์ ApplicationEvent ํด๋์ค๋ฅผ ์์ํด์ผ ํ์ผ๋ v4.2๋ถํฐ๋ ๋จ์ํ ๊ฐ์ฒด๋ ์ด๋ฒคํธ๋ก ๋ฐํํ ์ ์๊ฒ ๋์๋ค.
// Spring 4.2 ์ด์ : ApplicationEvent ์์ ํ์
public class OrderCompletedEvent extends ApplicationEvent {
private final Long orderId;
public OrderCompletedEvent(Object source, Long orderId) {
super(source);
this.orderId = orderId;
}
}
// 4.2 ์ดํ: ์๋ฌด POJO๋ ๋ฐ๋ก ๋ฐํ ๊ฐ๋ฅ
record OrderCompleted(Long orderId) {}
publisher.publishEvent(new OrderCompleted(1L));
๋ค๋ง ๋ด๋ถ ์ด๋ฒคํธ ์ ๋ฌ ์ฒด๊ณ๋ ์ฌ์ ํ ApplicationEvent ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๊ธฐ ๋๋ฌธ์, POJO๋ฅผ ์ง์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ฉด์๋ ๊ธฐ์กด ๋ฉ์ปค๋์ฆ๊ณผ ํธํ์ฑ์ ์ ์งํ๋ ค๋ฉด ์ค๊ฐ์ PayloadApplicationEvent๋ผ๋ ๋ํ์ด ํ์ํ๋ค. ์ด๋ฌํ ์ด์ ๋ก ์คํ๋ง์ ApplicationEvent๊ฐ ์๋ ์ผ๋ฐ ๊ฐ์ฒด๊ฐ ์ ๋ฌ๋๋ฉด ์ด๋ฅผ PayloadApplicationEvent๋ก ๊ฐ์ธ ๋ด๋ถ ์ด๋ฒคํธ ์ฒ๋ฆฌ ํ๋ฆ์ ๋ง์ถฐ ์ ํํ๋ค.
โข, โฃโฏ โฏSimpleApplicationEventMulticaster.multicastEvent()
์ด๋ฒคํธ๊ฐ ApplicationEventMulticaster์ ๋๋ฌํ๋ฉด, ๊ธฐ๋ณธ ๊ตฌํ์ฒด์ธ SimpleApplicationEventMulticaster๊ฐ ์ฌ์ฉ๋๊ณ , ํฌ๊ฒ ๋ค์๊ณผ ๊ฐ์ด ๋ ๊ฐ์ง ๋์์ด ์ผ์ด๋๋ค.
- ๋ฆฌ์ค๋ ๋ชฉ๋ก ๊ฒฐ์ – getApplicationListeners(event, type)๋ก ํ์ฌ ์ด๋ฒคํธ์ ๋ฐ์ํ ๋ฆฌ์ค๋๋ฅผ ํํฐ๋งํ๋ค.
- ์คํ ๋ฐฉ์ ๊ฒฐ์ – for-loop๋ฅผ ๋๋ฉฐ ๊ฐ ๋ฆฌ์ค๋๋ฅผ ๋๊ธฐ๋ก ํธ์ถํ ์ง ์ค๋ ๋ ํ์์ ๋น๋๊ธฐ๋ก ํธ์ถํ ์ง ํ๋จํ๋ค.
๊ทธ๋ฆฌ๊ณ ๋น๋๊ธฐ์ ์ ํ์ ์๋ ๋ ๊ฐ์ง ์กฐ๊ฑด์ ๋ง์กฑํ์ ๋ ์ด๋ฃจ์ด์ง๋ค.
์ฒซ ๋ฒ์งธ๋ TaskExecutor๊ฐ ์ค์ ๋์ด ์๋์ง ์ฌ๋ถ์ด๋ค. ์ปจํ ์คํธ ์ด๊ธฐํ ์ ์ด๋ฆ์ด applicationEventMulticaster ์ธ ๋น์ ์ง์ ๋ฑ๋กํ๊ณ setTaskExecutor(...)๋ก ์ค๋ ๋ ํ์ ์ฃผ์ ํ๋ฉด, ๋ฉํฐ์บ์คํฐ๋ ์ค๋ ๋ ํ์ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌํ ์ ์๊ฒ ๋๋ค. ๋น์ ๋ฐ๋ก ์ ์ํ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ SimpleApplicationEventMulticaster๊ฐ ์์ฑ๋๋๋ฐ, ์ด๋ taskExecutor == null์ด๋ฏ๋ก ๋ชจ๋ ๋ฆฌ์ค๋๋ ๋๊ธฐ๋ก ์คํ๋๋ค.
@Configuration
public class EventConfig {
// ์ค๋ ๋ ํ ์ ์
@Bean
public ThreadPoolTaskExecutor eventPool() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setCorePoolSize(4);
pool.setMaxPoolSize(8);
pool.initialize();
return pool;
}
// ์ ์ญ ์ด๋ฒคํธ ๋ฉํฐ์บ์คํฐ์ ์ค๋ ๋ ํ ์ฃผ์
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster multicaster(ThreadPoolTaskExecutor eventPool) {
var m = new SimpleApplicationEventMulticaster();
m.setTaskExecutor(eventPool); // ๋น๋๊ธฐ ์คํ ๊ฐ๋ฅ
return m;
}
}
์์ฒ๋ผ ์ค์ ํ ๊ฒฝ์ฐ, ๋ฉํฐ์บ์คํฐ๋ TaskExecutor๊ฐ ์์ผ๋ฏ๋ก ๋น๋๊ธฐ ์คํ์ด ๊ฐ๋ฅํ๋ค๊ณ ํ๋จํ๋ค. ๋ง์ฝ ์์ ๊ฐ์ด ๋ณ๋ ๋น ๋ฑ๋ก ์์ด ๊ธฐ๋ณธ ์ค์ ์ ์ฌ์ฉํ ๊ฒฝ์ฐ์๋ taskExecutor == null ์ํ๋ก ๋ฑ๋ก๋์ด ํญ์ ๋๊ธฐ๋ก ์คํ๋๋ค.(๋ค๋ง ๋๋ ์ง๊ธ๊น์ง ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ์์ ๊ฐ์ด applicationEventMulticaster๋ฅผ ์ง์ ์ ์ํ ๊ฒฝ์ฐ๋ ๋ณด์ง ๋ชปํ๋ค. ๋ณดํต Listener ์ธก์ @Async๋ฅผ ํตํด ๋น๋๊ธฐ๋ก ์ํํ๋ค.)
๋ ๋ฒ์งธ๋ ๊ฐ ๋ฆฌ์ค๋๊ฐ supportsAsyncExecution()์์ true๋ฅผ ๋ฐํํ๋์ง ์ฌ๋ถ์ด๋ค. ์ผ๋ฐ์ ์ธ @EventListener ๊ธฐ๋ฐ ๋ฆฌ์ค๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก true๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ์ง๋ง, @TransactionalEventListener์ ๊ฒฝ์ฐ์๋ ํธ๋์ญ์ ๋ณด์ฅ์ ์ํด ์ค์ ๋ก ๋ด๋ถ ๊ตฌํ์์๋ supportsAsyncExecution()์ด false๋ก ๊ณ ์ ๋์ด false๋ฅผ ๋ฐํํ๋ค. ๋ค์ ์ฝ๋๋ค์ ์ดํด๋ณด์.
@Component
public class MailNotifier {
@EventListener
public void handle(OrderCompletedEvent e) {
// ๋น๋๊ธฐ ์คํ ๊ฐ๋ฅ (์ ์ญ ํ์ด ์์ ๊ฒฝ์ฐ)
}
}
๋ง์ฝ applicationEventMulticaster ๋น์ ์ค๋ ๋ ํ์ ์ฃผ์ ํด ์ฃผ์๋ค๋ฉด ์ ๋ฉ์๋๋ ๋น๋๊ธฐ๋ก ์คํ๋ ๊ฒ์ด๊ณ , ๊ทธ๋ ์ง ์๋ค๋ฉด ํธ์ถ ์ค๋ ๋์์ ๋๊ธฐ๋ก ์คํ๋๋ค.
@EnableAsync
@Component
public class SmsNotifier {
@Async
@EventListener
public void sendSms(OrderCompletedEvent e) {
// ๋ฉํฐ์บ์คํฐ๋ ๋๊ธฐ ํธ์ถํ์ง๋ง, @Async ๋๋ถ์ ๋ฉ์๋ ๋ณธ๋ฌธ๋ง ๋ณ๋ ํ์์ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌ
}
@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void sendSms(OrderCompletedEvent e) {
// supportsAsyncExecution() == false ์ด๋ฏ๋ก ํธ์ถ ์์ฒด๋ ํธ์ถ ์ค๋ ๋
// ๊ทธ๋ฌ๋ @Async ๋ก ์ธํด ๋ณ๋ ํ์์ ์คํ
}
}
๋ณดํต์ ์ด๋ ๊ฒ @Async ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด์ ๋น๋๊ธฐ๋ก ์์ ์ ํ ๊ฒ์ด๋ค. ์ด ๊ฒฝ์ฐ ๋ฉํฐ์บ์คํฐ๋ ๋๊ธฐ์ ์ผ๋ก ํธ์ถํ์ง๋ง, @Async ๋๋ถ์ ๋ณธ๋ฌธ์ ๋ณ๋ ์ค๋ ๋ ํ์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋๋ฉฐ, ์ ์ญ TaskExecutor ์ค์ ๊ณผ๋ ๋ฌด๊ดํ๊ฒ ๋น๋๊ธฐํ๊ฐ ๊ฐ๋ฅํ๋ค.
โคโฏSimpleApplicationEventMulticaster.invokeListener()
์ด ๋จ๊ณ๋ ๋ฆฌ์ค๋ ๋ฉ์๋๋ฅผ ์ ๋ง๋ก ํธ์ถํ๋ ๋ง์ง๋ง ์ง์ ์ ์ด๋ค. ์ด ๋ฉ์๋์์ ๋ค์๊ณผ ๊ฐ์ ๋์์ด ์ํ๋๋ค.
- ErrorHandler๊ฐ ์์(๊ธฐ๋ณธ) : ๋๊ธฐ ์คํ์ผ ๊ฒฝ์ฐ ์์ธ๊ฐ ๋ฐ์ํ ๋ฆฌ์ค๋์์ ์ฆ์ ์์๋ก ์ ํ๋๊ณ , ์ดํ ๋ฆฌ์ค๋๋ ์คํ๋์ง ์๋๋ค. ๋น๋๊ธฐ ์คํ์ผ ๊ฒฝ์ฐ์๋ ๊ฐ ๋ฆฌ์ค๋๊ฐ ๋ณ๋ ์ค๋ ๋์์ ์คํ๋๋ฏ๋ก, ํ ๋ฆฌ์ค๋์ ์์ธ๊ฐ ๋ค๋ฅธ ๋ฆฌ์ค๋ ์คํ์ ์ํฅ์ ์ฃผ์ง ์๋๋ค.
- ErrorHandler๊ฐ ์์ : ์์ธ๋ฅผ ํธ๋ค๋ฌ๋ก ์์ํ์ฌ ๋ก๊น ํ๊ฑฐ๋ ๋ฌด์ํ ์ ์์ผ๋ฉฐ, ๋ค๋ฅธ ๋ฆฌ์ค๋๋ค์ ์คํ์ด ๊ณ์ ์งํ๋๋ค.
์ดํ doInvokeListener(listener, event)๋ฅผ ํตํด ์ค์ ๋ก ApplicationListener.onApplicationEvent()๊ฐ ํธ์ถ๋๋ค. ์ด ๋ฉ์๋ ์์์๋ ๋ฆฌ์ค๋ ํ์ ๊ณผ ์ด๋ฒคํธ ํ์ ์ด ์ผ์นํ์ง ์์ ClassCastException์ด ๋ฐ์ํ ์ ์๋๋ฐ, ํ์ ๋ถ์ผ์น์ผ ๊ฒฝ์ฐ TRACE ๋ก๊ทธ๋ง ๋จ๊ธฐ๊ณ ์กฐ์ฉํ ์์ธ๋ฅผ ๋ฌด์ํ๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ ์์ธ๋ฅผ ๋ค์ ๋์ ธ ํธ์ถ์์๊ฒ ์๋ฆฐ๋ค.
๋ํ ์ด๋ฒคํธ๊ฐ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌ๋๋๋ก ์ค์ ๋์๋๋ผ๋, ์ค๋ ๋ ํ์ด ๊ฐ๋ ์ฐจ๊ฑฐ๋ ์ข ๋ฃ๋์ด RejectedExecutionException์ด ๋ฐ์ํ ๊ฒฝ์ฐ, ์คํ๋ง์ ์ด ์์ธ๋ฅผ ๊ทธ๋๋ก ๋์ง์ง ์๊ณ ํ์ฌ ์ค๋ ๋์์ ๋๊ธฐ์ ์ผ๋ก ์ด๋ฒคํธ๋ฅผ ์คํํ๋ ๋ฐฉ์์ผ๋ก ์ฐํ ์ฒ๋ฆฌํ๋ค. ์ด๋ก์จ ์ ํ๋ฆฌ์ผ์ด์ ์ข ๋ฃ ์์ ๋ฑ์์๋ ์ด๋ฒคํธ ์์ค ์์ด ์์ ํ ์ฒ๋ฆฌ๋ฅผ ๋ณด์ฅํ ์ ์๋ค.
โฅโฏ๋ฆฌ์ค๋ ์ํ
๋ฉํฐ์บ์คํฐ๋ ์ต์ข ์ ์ผ๋ก ์ด๋ํฐ๋ฅผ ํตํด ํด๋น @EventListener ๋๋ @TransactionalEventListener ๋ฉ์๋๋ฅผ ์คํํ๋ค. ์ฐธ๊ณ ๋ก @TransactionalEventListener ๊ฐ์ ๊ฒฝ์ฐ๋ phase ์์ฑ์ ๋ฐ๋ผ ์ด๋ฒคํธ ๋ฆฌ์ค๋์ ์คํ ์์ ์ ์ง์ฐ์ํฌ ์ ์๋ค.
๊ทธ๋ผ ์ฌ๊ธฐ์ "@TransactionalEventListener๋ ์ด๋ป๊ฒ ๋ฉํฐ์บ์คํฐ ๋จ๊ณ์์ ๋ฐ๋ก ์คํ๋์ง ์๊ณ phase ์ค์ ์ ๋ฐ๋ผ ์คํ ์์ ์ ๋ฏธ๋ฃฐ ์ ์์๊น?" ํ๋ ๊ถ๊ธ์ฆ์ด ๋ค ์ ์์ํ ๋ฐ, ์ด ์ง๋ฌธ์ ๋ํ ์ ๋ต์ @TransactionalEventListener๋ฅผ ๊ฐ์ธ๋ ๋ด๋ถ ์ด๋ํฐ ํด๋์ค์ธ TransactionalApplicationListenerMethodAdapter.java์ ์๋ค.
SimpleApplicationEventMulticaster๋ ๋ชจ๋ ๋ฆฌ์ค๋์ ๋ํด ๋จ์ํ onApplicationEvent() ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ฟ์ด๋ค. ๊ทธ๋ฐ๋ฐ @TransactionalEventListener์ ๊ฒฝ์ฐ๋ ์ด ์ด๋ํฐ๊ฐ ํด๋น ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ณ ์์ด์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํด๋ ๋ฆฌ์ค๋ ๋ฉ์๋๋ฅผ ์ฆ์ ์คํํ์ง ์๊ณ , ํธ๋์ญ์ ์ ํ์ ๋์์ผ๋ก ๋ฑ๋ก๋ง ํด๋๋ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ๋๋ค. ๋ฑ๋ก ํ์ โฏSimpleApplicationEventMulticaster์ ์ญํ ์ ๋์ด๋๋ค.
๋ ์์ธํ ์ค๋ช
ํ๋ฉด ํด๋น ๋ณธ๋ฌธ์ ์ฃผ์ ๋ฅผ ๋ฒ์ด๋๋ ๊ฒ ๊ฐ์ ๊ฐ๋ตํ๊ฒ๋ง ์ดํด๋ณด๋ฉด AFTER_COMMIT๋ก ๋ฑ๋ก๋ ๋ฆฌ์ค๋๋ ์ด๋ฒคํธ๊ฐ ๋ฐํ๋๋๋ผ๋ ์ฆ์ ์คํ๋์ง ์๊ณ , TransactionSynchronizationManager๋ฅผ ํตํด ํด๋น ๋ฆฌ์ค๋๋ฅผ ํธ๋์ญ์
ํ์ ์์
์ผ๋ก ์ฌ์ฉํ ์ ์๋ ์ฝ๋ฐฑ ๊ฐ์ฒด(TransactionalApplicationListenerSynchronization)๋ก ๋ฑ๋กํด ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํธ๋์ญ์
์ด ์ปค๋ฐ๋๋ ์์ ์ด ๋๋ฉด PlatformTransactionManager๋ ๋ฑ๋ก๋ ์ฝ๋ฐฑ๋ค์ afterCommit() ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ,
๊ทธ ์์์ listener.processEvent(event) → invokeListenerMethod()๋ฅผ ํตํด ์ต์ข
์ ์ผ๋ก ๋ฆฌ์ค๋ ๋ฉ์๋๊ฐ ์คํ๋๋ค.
'BackEnd๐ฑ > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋๋ GET์ผ๋ก ๋ณด๋๋๋ฐ ์ POST๋ก ๊ฐ๊น? (feat. OpenFeign ๊ธฐ์ฌ) (0) | 2025.05.26 |
---|---|
Hibernate 5.x โ 6.x QueryDSL ๊ด๋ จ ์ด์ (0) | 2025.03.28 |
Spring ํธ๋์ญ์ ์ ์ธ์ ์ด๋ป๊ฒ ๋กค๋ฐฑ ๋ ๊น? -2ํธ(feat. rollback-only) (1) | 2024.12.22 |
Spring ํธ๋์ญ์ ์ ์ธ์ ์ด๋ป๊ฒ ๋กค๋ฐฑ ๋ ๊น? -1ํธ (2) | 2024.10.04 |
[gradle] implementation, api ์ฐจ์ด (0) | 2024.09.07 |
[JPA] deleteAll(), deleteAllInBatch(), deleteInBatch() ์ ๋ฆฌ (0) | 2024.08.12 |
๋๊ธ