Spring Events

 

Event 처리

여러 비즈니스 로직을 이벤트를 활용하여 처리가능하다. 기존과 달리 Pub/Sub 형태이기 때문에 느슨하게 결합할 수 있다.

 

Event

Spring 4.2 버전 이후 POJO 스타일로 사용가능하다. 이전 버전에서는 ApplicationEvent를 상속받아 구현해야 한다.

@Getter
@Setter
@NoArgsConstructor
public abstract class BaseEvent {
}

@Getter
@Setter
@NoArgsConstructor
public class OrderEvent extends BaseEvent {
}

@Getter
@Setter
@NoArgsConstructor
public class UserEvent extends BaseEvent {
}

 

Publish

ApplicationEventPublishervoid publishEvent(Object event)를 활용하여 이벤트를 발생시킬 수 있다.

@Component
public class EventPublisher {

	final
	ApplicationEventPublisher applicationEventPublisher;

	public EventPublisher(
		ApplicationEventPublisher applicationEventPublisher) {
		this.applicationEventPublisher = applicationEventPublisher;
	}

	public <T extends BaseEvent> void publish(T event) {
		applicationEventPublisher.publishEvent(event);
	}
}

 

Subscribe

Spring 4.2 버전 이후 @EventListener 를 통해서 이벤트를 수신받을 수 있다. 이전 버전에서는 ApplicationListener<E>를 구현해야 한다.

@Component
public class OrderListener {

	@EventListener
	public void handleOrder(OrderEvent orderEvent) throws Exception {
		Thread.sleep(2000);
		System.out.println(System.currentTimeMillis() + " handleOrder");
	}
}

@Component
public class UserListener {

	@EventListener
	public void handleUser(UserEvent userEvent) throws Exception {
		Thread.sleep(1000);
		System.out.println(System.currentTimeMillis() + " handleUser");
	}

	@EventListener
	public void handleUserOrder(OrderEvent orderEvent) throws Exception {
		Thread.sleep(3000);
		System.out.println(System.currentTimeMillis() + " handleUserOrder");
	}
}

 

예시

@Test
public void orderEvent() throws Exception {
	OrderEvent orderEvent = new OrderEvent();

	System.out.println(System.currentTimeMillis() + " START");
	eventPublisher.publish(orderEvent);
	System.out.println(System.currentTimeMillis() + " END");

	Thread.sleep(5000);
}

/* Results 순서는 상이할 수 있음
1620656350473 START
1620656352486 handleOrder
1620656355499 handleUserOrder
1620656355499 END
*/

@Test
public void event() throws Exception {
	OrderEvent orderEvent = new OrderEvent();
	UserEvent userEvent = new UserEvent();

	System.out.println(System.currentTimeMillis() + " START");
	eventPublisher.publish(orderEvent);
	System.out.println(System.currentTimeMillis() + " DIVIDER");
	eventPublisher.publish(userEvent);
	System.out.println(System.currentTimeMillis() + " END");

	Thread.sleep(5000);
}

/* Results orderEvent의 순서는 상이할 수 있음
1620656315234 START
1620656317237 handleOrder
1620656320238 handleUserOrder
1620656320238 DIVIDER
1620656321248 handleUser
1620656321248 END
*/

 

Event 순서 처리

동일 Event의 처리에 있어 순서를 정하기 위해선 @EventListener@Order를 추가, 활용해야 한다. 숫자가 낮을 수록 우선순위가 높다.

@Component
public class OrderListener {

	@Order(2)
	@EventListener
	public void handleOrder(OrderEvent orderEvent) throws Exception {
		Thread.sleep(2000);
		System.out.println(System.currentTimeMillis() + " handleOrder");
	}
}

@Component
public class UserListener {

	@Order(0)
	@EventListener
	public void handleUser(UserEvent userEvent) throws Exception {
		Thread.sleep(1000);
		System.out.println(System.currentTimeMillis() + " handleUser");
	}

	@Order(1)
	@EventListener
	public void handleUserOrder(OrderEvent orderEvent) throws Exception {
		Thread.sleep(3000);
		System.out.println(System.currentTimeMillis() + " handleUserOrder");
	}
}

 

예시

@Test
public void orderEvent() throws Exception {
	OrderEvent orderEvent = new OrderEvent();

	System.out.println(System.currentTimeMillis() + " START");
	eventPublisher.publish(orderEvent);
	System.out.println(System.currentTimeMillis() + " END");

	Thread.sleep(5000);
}

/* Results
1620656219744 START
1620656222754 handleUserOrder
1620656224760 handleOrder
1620656224760 END
*/

@Test
public void event() throws Exception {
	OrderEvent orderEvent = new OrderEvent();
	UserEvent userEvent = new UserEvent();

	System.out.println(System.currentTimeMillis() + " START");
	eventPublisher.publish(orderEvent);
	System.out.println(System.currentTimeMillis() + " DIVIDER");
	eventPublisher.publish(userEvent);
	System.out.println(System.currentTimeMillis() + " END");

	Thread.sleep(5000);
}

/* Results
1620656258732 START
1620656261740 handleUserOrder
1620656263752 handleOrder
1620656263752 DIVIDER
1620656264760 handleUser
1620656264760 END
*/

 

Event 비동기 처리

Spring 설정 클래스에 @EnableAsync를 추가하고, @EventListener@Async를 추가, 활용해야 한다.

@EnableAsync
@SpringBootApplication
public class EventExampleApplication {

	public static void main(String[] args) {
		SpringApplication.run(EventExampleApplication.class, args);
	}
}
@Component
public class OrderListener {

	@Async
	@EventListener
	public void handleOrder(OrderEvent orderEvent) throws Exception {
		Thread.sleep(2000);
		System.out.println(System.currentTimeMillis() + " handleOrder");
	}
}

@Component
public class UserListener {

	@Async
	@EventListener
	public void handleUser(UserEvent userEvent) throws Exception {
		Thread.sleep(1000);
		System.out.println(System.currentTimeMillis() + " handleUser");
	}

	@Async
	@EventListener
	public void handleUserOrder(OrderEvent orderEvent) throws Exception {
		Thread.sleep(3000);
		System.out.println(System.currentTimeMillis() + " handleUserOrder");
	}
}

 

예시

@Test
public void orderEvent() throws Exception {
	OrderEvent orderEvent = new OrderEvent();

	System.out.println(System.currentTimeMillis() + " START");
	eventPublisher.publish(orderEvent);
	System.out.println(System.currentTimeMillis() + " END");

	Thread.sleep(5000);
}

/* Results
1620656121067 START
1620656121070 END
1620656123098 handleOrder
1620656124091 handleUserOrder
*/

@Test
public void event() throws Exception {
	OrderEvent orderEvent = new OrderEvent();
	UserEvent userEvent = new UserEvent();

	System.out.println(System.currentTimeMillis() + " START");
	eventPublisher.publish(orderEvent);
	System.out.println(System.currentTimeMillis() + " DIVIDER");
	eventPublisher.publish(userEvent);
	System.out.println(System.currentTimeMillis() + " END");

	Thread.sleep(5000);
}

/* Results
1620656048705 START
1620656048707 DIVIDER
1620656048708 END
1620656049721 handleUser
1620656050718 handleOrder
1620656051715 handleUserOrder
*/

Leave a comment