[Event] Spring Event๋ž€? ์ด๋ฒคํŠธ ๋ฐœํ–‰๊ณผ ๊ตฌ๋… ๋ฐฉ๋ฒ•

 

1. ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

Spring Boot์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋“ค์–ด๊ฐ€๊ธฐ ์ „์—, ์ด๋ฒคํŠธ๋ฅผ ์™œ ์จ์•ผํ•˜๋Š”์ง€, ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€ ์ƒํ™ฉ์— ๋Œ€ํ•ด ๋จผ์ € ์•Œ์•„๋ณด์ž. ํšŒ์›๊ฐ€์ž…์„ ํ•˜๊ณ  ๋‚˜๋ฉด ๊ฐ€์ž… ์ถ•ํ•˜ ๋ฉ”์„ธ์ง€๋ฅผ ์ „์†กํ•˜๋Š” ๋™์‹œ์— ์ฟ ํฐ์„ ์ „์†กํ•˜๋Š” ์„œ๋น„์Šค๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์•˜๋‹ค.

 

@Service
@RequiredArgsConstructor
public class MemberService {

    private final AlarmService alarmService;
    private final AlimTalkService alimTalkService;

    public void register(String name) {
        // ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ๋กœ์ง
        System.out.println("ํšŒ์› ์ถ”๊ฐ€ ์™„๋ฃŒ");

        // ๊ฐ€์ž… ์ถ•ํ•˜ ํ‘ธ์‹œ ์•Œ๋ฆผ
        alarmService.send(name);

        // ์นด์นด์˜ค ์•Œ๋ฆผํ†ก ์ „์†ก
        alimTalkService.send(name);
    }
}

 

์ฝ”๋“œ๋กœ ๊ฐ„๋žตํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ์ฝ”๋“œ์—” ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ์ ์ด ์žˆ๋‹ค.

 

1) ๊ฐ•ํ•œ ๊ฒฐํ•ฉ

ํ˜„์žฌ ํšŒ์›๊ฐ€์ž… ์„œ๋น„์Šค์— ํšŒ์› ๊ฐ€์ž… ๋กœ์ง๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ฐ€์ž… ์ถ•ํ•˜ ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๋กœ์ง, ์นด์นด์˜ค ์•Œ๋ฆผํ†ก ์ „์†กํ•˜๋Š” ๋กœ์ง์ด ๋ชจ๋‘ ์„ž์—ฌ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์„œ๋กœ ๊ฐ•ํ•œ ๊ฒฐํ•ฉ์œผ๋กœ ๋ฌถ์—ฌ์žˆ์œผ๋ฉด ํ›„์— ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๊ณ  ์ฝ”๋“œ์˜ ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•˜๋‹ค.

 

2) ์„ฑ๋Šฅ

์‹ค์ œ๋ก  ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ๋Š” ์—†๊ฒ ์ง€๋งŒ ๊ฐ€์ž… ์ถ•ํ•˜ ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š”๋ฐ 3๋ถ„, ์•Œ๋ฆผํ†ก์„ ๋ณด๋‚ด๋Š”๋ฐ 3๋ถ„์ด ๊ฑธ๋ฆฐ๋‹ค๊ณ  ํ•˜๋ฉด ์ด ํšŒ์›๊ฐ€์ž…์€ 6๋ถ„์ด ๊ฑธ๋ฆฌ๊ฒŒ ๋œ๋‹ค. ๋ฉ”์ธ ์ด๋ฒคํŠธ์ธ ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ๋กœ์ง์„ ๋๋‚ด๋ฉด ์„œ๋ธŒ ์ด๋ฒคํŠธ์ธ ๊ฐ€์ž… ์ถ•ํ•˜ ๋ฉ”์„ธ์ง€ ์ „์†ก์ด๋‚˜ ๊ฐ€์ž… ์ถ•ํ•˜ ์ฟ ํฐ์€ ์ „์†ก์™„๋ฃŒ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ํ•„์š”๊ฐ€ ์—†๋‹ค.

 

3) ํŠธ๋žœ์žญ์…˜

์œ„ ๋กœ์ง์—์„œ ๋งŒ์•ฝ ์•Œ๋ฆผํ†ก์„ ์ „์†กํ•˜๋‹ค ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋ฉด ์–ด๋–ป๊ฒŒ๋ ๊นŒ?? ํ•œ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ์—ฌ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด์ „์— ์ฒ˜๋ฆฌํ•œ ๋กœ์ง๋“ค๊นŒ์ง€ ์ „๋ถ€ ๋กค๋ฐฑ๋œ๋‹ค. ์ฐจ๋ผ๋ฆฌ ํšŒ์› ๊ฐ€์ž… ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ณ , ํ‘ธ์‹œ์•Œ๋ฆผ๊ณผ ์•Œ๋ฆผํ†ก์„ ๋”ฐ๋กœ ๊ด€๋ฆฌํ•˜๋Š”๊ฒŒ ์˜ณ์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

๋ฐ”๋กœ ์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘์— ์ด๋ฒคํŠธ๋ฅผ ์ ์šฉํ•ด์„œ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์ด๋ฒคํŠธ๋Š” ์ƒ์„ฑ ์ฃผ์ฒด์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•ด์„œ ํ›„์ฒ˜๋ฆฌ๋ฅผ ๋„์™€์ค€๋‹ค.

 

 

 

2. ์ด๋ฒคํŠธ์˜ ์‹คํ–‰ ๋‹จ๊ณ„

  1. ์ƒ์„ฑ ์ฃผ์ฒด(์ฃผ๋กœ ๋„๋ฉ”์ธ ๊ฐ์ฒด)์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒํ•˜๋ฉด ์ด๋ฒคํŠธ ๋””์ŠคํŒจ์ฒ˜์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.
  2. ์ด๋ฒคํŠธ ๋””์ŠคํŒจ์ฒ˜๊ฐ€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์—ฐ๊ฒฐํ•ด์ค€๋‹ค.
  3. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์ด๋ฒคํŠธ์— ๋‹ด๊ธด ๋ฐ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•œ๋‹ค.

 

 

3.1 ๊ฐ•ํ•œ ๊ฒฐํ•ฉ ํ•ด๊ฒฐ

์ด์ œ Spring Event๋ฅผ ์ด์šฉํ•ด ๋ฌธ์ œ์ ๋“ค์„ ํ•˜๋‚˜ํ•˜๋‚˜ ํ•ด๊ฒฐํ•ด๋‚˜๊ฐ€ ๋ณด์ž.

 

- ์ด๋ฒคํŠธ ํด๋ž˜์Šค ์ƒ์„ฑ

public class RegisteredEvent {

  private String name;

  public RegisteredEvent(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }
}

 

์ด๋ฒคํŠธ๋Š” ์ƒํƒœ๊ฐ€ ๋ฐ”๋€ ํ›„์— ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฒคํŠธ ํด๋ž˜์Šค์˜ ์ด๋ฆ„์€ ๊ณผ๊ฑฐ์‹œ์ œ๋กœ ์ง€์–ด์•ผํ•œ๋‹ค. ๋˜ํ•œ, ์ด๋ฒคํŠธ ํด๋ž˜์Šค๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•œ๋‹ค.

์˜ˆ์ œ์—์„  ํŠน์ • ํšŒ์›์—๊ฒŒ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๊ธฐ ์œ„ํ•ด์„  ์ •๋ณด๊ฐ€ ํ•„์š”ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— name์„ ํ•„๋“œ๋กœ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค.

 

 

- ๊ธฐ์กด์˜ MemberService ์ˆ˜์ •

@Service
@RequiredArgsConstructor
public class MemberService {

//    private final AlarmService alarmService;
//    private final AlimTalkService alimTalkService;

    private final ApplicationEventPublisher publisher;

    public void register(String name) {
        // ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ๋กœ์ง
        System.out.println("ํšŒ์› ์ถ”๊ฐ€ ์™„๋ฃŒ");

        // ์ด๋ฒคํŠธ ๋“ฑ๋ก
        publisher.publishEvent(new RegisteredEvent(name));

//        // ๊ฐ€์ž… ์ถ•ํ•˜ ํ‘ธ์‹œ ์•Œ๋ฆผ
//        alarmService.send(name);
//
//        // ์นด์นด์˜ค ์•Œ๋ฆผํ†ก ์ „์†ก
//        alimTalkService.send(name);
    }
}

 

์ด๋ฒคํŠธ๋ฅผ ๋ณด๋‚ด๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ApplicationEventPublisher๋ฅผ ์ฃผ์ž…ํ•ด์ฃผ์—ˆ๊ณ ,

ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ๋ฅผ ์™„๋ฃŒํ•˜๋ฉด, publishEvent๋ฅผ ์‚ฌ์šฉํ•ด ์ด๋ฒคํŠธ๋ฅผ ๋ฐœํ–‰ํ•ด์ค€๋‹ค.

๊ธฐ์กด์— ์žˆ์—ˆ๋˜ ์•Œ๋ฆผ ์„œ๋น„์Šค์™€์˜ ์˜์กด๊ด€๊ณ„๋Š” ์ œ๊ฑฐํ•˜์˜€๋‹ค.

 

 

- ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋“ฑ๋ก

@Component
@RequiredArgsConstructor
public class SmsEventHandler {

    private final AlarmService alarmService;
    private final AlimTalkService alimTalkService;

    @EventListener
    public void sendFCM(RegisteredEvent event) {
        System.out.println("[SmsEventHandler - sendFCM]");
        alarmService.send(event.getName());
    }

    @EventListener
    public void sendAlimTalk(RegisteredEvent event) {
        System.out.println("[SmsEventHandler - sendAlimTalk]");
        alimTalkService.send(event.getName());
    }
}

 

@EventListener๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋กœ ๋“ฑ๋ก์ด ๋˜๊ณ , ๋งค๊ฐœ๋ณ€์ˆ˜์— ์ด๋ฒคํŠธ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜๋ฉด ํ•ด๋‹น ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ˆ˜์‹ ํ•ด์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

- ํ…Œ์ŠคํŠธ

@Test
@DisplayName("ํšŒ์› ๊ฐ€์ž… ํ…Œ์ŠคํŠธ")
void register() {
    String name = "dgjinsu";

    memberService.register(name);
}

 

๊ฐ„๋‹จํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋กœ๊ทธ๊ฐ€ ์ฐํžˆ๋Š”๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ ๋™์ผํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ์ปดํฌ๋„ŒํŠธ๊ฐ„ ๊ฒฐํ•ฉ๋„๋Š” ๋‚ฎ์ถœ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

 

 

 

3.2 ์„ฑ๋Šฅ ๋ฌธ์ œ ํ•ด๊ฒฐ

์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๊ฐ service ๋กœ์ง์— ์ž„์‹œ๋กœ ์“ฐ๋ ˆ๋“œ ์Šฌ๋ฆฝ์„ ๊ฑธ์–ด์ฃผ์–ด ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ƒํ™ฉ์ด๋ผ ๊ฐ€์ •ํ•ด๋ณด์•˜๋‹ค.

 

@Service
public class AlarmService {
    public void send(String name) throws InterruptedException {
        Thread.sleep(3000); // 3์ดˆ sleep
        System.out.println(name + "์—๊ฒŒ push ์•Œ๋ฆผ ๋ฐœ์†ก");
    }
}

@Service
public class AlimTalkService {
    public void send(String name) throws InterruptedException {
        Thread.sleep(3000); // 3์ดˆ sleep
        System.out.println(name + "์—๊ฒŒ ์•Œ๋ฆผํ†ก ๋ฐœ์†ก");
    }
}

 

 

client ์ž…์žฅ์—์„  ํšŒ์›๊ฐ€์ž…์„ ์š”์ฒญํ•˜๊ณ  ์•ฝ 6์ดˆ ๋’ค ์™„๋ฃŒ ํ™”๋ฉด์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

@EnableAsync ์™€ @Async ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ๋ฉด ํ•ด๊ฒฐ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

@SpringBootApplication
@EnableAsync // ์ถ”๊ฐ€
public class TestApplication {
    public static void main(String[] args) {
       SpringApplication.run(TestApplication.class, args);
    }
}


@Component
@RequiredArgsConstructor
public class SmsEventHandler {

    private final AlarmService alarmService;
    private final AlimTalkService alimTalkService;

    @Async // ์ถ”๊ฐ€
    @EventListener
    public void sendFCM(RegisteredEvent event) throws InterruptedException {
        System.out.println("[SmsEventHandler - sendFCM]");
        alarmService.send(event.getName());
    }

    @Async // ์ถ”๊ฐ€
    @EventListener
    public void sendAlimTalk(RegisteredEvent event) throws InterruptedException {
        System.out.println("[SmsEventHandler - sendAlimTalk]");
        alimTalkService.send(event.getName());
    }
}

 

๊ฒฐ๊ณผ๋Š” 2ms๋กœ ํ‘ธ์‹œ ์•Œ๋ฆผ ๋กœ์ง๊ณผ ์•Œ๋ฆผํ†ก ๋กœ์ง์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ๋ชจ์Šต์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

 

3.3 ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ

ํŠธ๋žœ์žญ์…˜์„ ๋ถ„๋ฆฌํ•ด ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๊ธฐ์— ์•ž์„œ ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•ด ๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด์ž. 

A,B๋Š” ๊ฐ๊ฐ ํŠธ๋žœ์žญ์…˜ ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์–ด์žˆ๋‹ค. Aํ•จ์ˆ˜์—์„œ Bํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ–ˆ๊ณ  Bํ•จ์ˆ˜์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด Aํ•จ์ˆ˜๋„ ๋กค๋ฐฑ์ด ๋ ๊นŒ?? 

@Service
@RequiredArgsConstructor
@Transactional
public class MemberService {

    private final PlatformTransactionManager transactionManager;
    private final TestService testService;

    public void register(String name) {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(def);

        try {
            testService.a();

            // ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹
            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            System.out.println("ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ");
        }
    }
    
    
    
@Service
public class TestService {

    public void a() throws Exception {
        Thread.sleep(3000);
        throw new Exception("์—๋Ÿฌ");
    }
}

 

aํ•จ์ˆ˜์—์„œ ๋ณ„๋„๋กœ propagation์„ ์„ค์ •ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— A ํ•จ์ˆ˜์˜ ํŠธ๋žœ์žญ์…˜๊ณผ B ํ•จ์ˆ˜์˜ ํŠธ๋žœ์žญ์…˜์€ ๋™์ผํ•œ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•˜๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ B ํ•จ์ˆ˜์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด A ํ•จ์ˆ˜์˜ ํŠธ๋žœ์žญ์…˜๋„ ๋กค๋ฐฑ๋œ๋‹ค.

 

ํžˆ์ง€๋งŒ aํ•จ์ˆ˜๊ฐ€ @Async๋กœ ์‹คํ–‰๋œ๋‹ค๋ฉด ์ƒํ™ฉ์ด ๋‹ฌ๋ผ์ง„๋‹ค. 

 

๋น„๋™๊ธฐ ํ˜ธ์ถœ์˜ ๊ฒฝ์šฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ ํŠธ๋žœ์žญ์…˜ ์ปจํ…์ŠคํŠธ๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๋Š” ์ฃผ๋กœ ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ์— ๋Œ€ํ•œ ํŠธ๋žœ์žญ์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉฐ, ๋น„๋™๊ธฐ์ ์ธ ํ˜ธ์ถœ์€ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ A ํ•จ์ˆ˜์™€ B ํ•จ์ˆ˜๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋  ๊ฒฝ์šฐ, ํŠธ๋žœ์žญ์…˜ ์ปจํ…์ŠคํŠธ๊ฐ€ ๊ณต์œ ๋˜์ง€ ์•Š์•„ B์˜ ์˜ˆ์™ธ๊ฐ€ A์˜ ํŠธ๋žœ์žญ์…˜ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค.

 

๊ฒฐ๊ณผ์ ์œผ๋กœ @Async๋ฅผ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์•Œ๋ฆผ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ๊ฒฝ์šฐ ๋ณ„๋‹ค๋ฅธ ์„ค์ •์„ ํ•˜์ง€ ์•Š์•„๋„ ํŠธ๋žœ์žญ์…˜์ด ๋ถ„๋ฆฌ๋œ๋‹ค. 

 

ํ•˜์ง€๋งŒ ํŠธ๋žœ์žญ์…˜ ๋ถ„๋ฆฌํ•œ๋‹ค๊ณ  ๋‹ค ํ•ด๊ฒฐ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. 

๋‚˜์˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์•˜์„ ๋•Œ ํšŒ์›๊ฐ€์ž…์ด ์™„๋ฃŒ๋˜์•ผ ์•Œ๋ฆผ ๋กœ์ง์ด ์‹คํ–‰๋˜์•ผ ํ•˜๋Š”๋ฐ, ํšŒ์›๊ฐ€์ž…์ด ์‹คํŒจํ•ด๋„ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•ด๋’€๊ธฐ ๋•Œ๋ฌธ์— ์•Œ๋ฆผ ๋กœ์ง์ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.

 

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•๋„ ๋ฌผ๋ก  ์žˆ๋‹ค. 

์ด๋ถ€๋ถ„์€ ๊ธ€์ด ๊ธธ์–ด์ ธ ์•„๋ž˜ ํฌ์ŠคํŒ…์—์„œ ์ž์„ธํ•˜๊ฒŒ ๋‹ค๋ค„๋ดค์Œ

 

https://dgjinsu.tistory.com/42

 

[Event] Spring Event ๋„์ž… ์‹œ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ

1. ์„œ๋ก  ์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ Spring Event๋กœ ์˜์กด์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ๋ฒ•์„ ๋‹ค๋ค„๋ณด์•˜๋‹ค. ํ•˜์ง€๋งŒ ํ•œ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ฒ˜๋ฆฌํ•˜๋˜ ๊ฒƒ๋“ค์ด ํฉ์–ด์ง€๋ฉด์„œ ๋ฌธ์ œ๋˜๋Š” ๋ถ€๋ถ„๋„ ์žˆ๋‹ค. ์ด๋ฒˆ์—” ๊ทธ ๋ถ€๋ถ„์„ ๊นŠ๊ฒŒ ๋‹ค๋ค„๋ณผ ์ƒ๊ฐ์ด๋‹ค

dgjinsu.tistory.com