DevLog ๐Ÿ˜ถ

[Spring] ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ, ๋นˆ ์Šค์ฝ”ํ”„ ๋ณธ๋ฌธ

Back-end/Spring

[Spring] ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ, ๋นˆ ์Šค์ฝ”ํ”„

dolmeng2 2022. 8. 7. 22:58

- ๊น€์˜ํ•œ ๋‹˜์˜ '์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ'์„ ๋ณด๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค ๐Ÿ˜Š

 

์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์Šคํ”„๋ง ์ž…๋ฌธ์ž๊ฐ€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ณ , ์Šคํ”„๋ง ๊ธฐ๋ณธ๊ธฐ๋ฅผ ํ™•์‹คํžˆ ๋‹ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., - ๊ฐ•์˜ ์†Œ๊ฐœ | ์ธํ”„๋Ÿฐ...

www.inflearn.com


- ์ง€๋‚œ ํฌ์ŠคํŒ…๊ณผ ์ด์–ด์ง‘๋‹ˆ๋‹ค :D

 

[Spring] ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž…

- ๊น€์˜ํ•œ ๋‹˜์˜ '์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ'์„ ๋ณด๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค ๐Ÿ˜Š ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜ ์Šคํ”„๋ง ์ž…๋ฌธ์ž๊ฐ€ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ณ , ์Šคํ”„๋ง

cl8d.tistory.com

- ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ ๊ฐ•์˜์˜ ๋งˆ์ง€๋ง‰ ์ •๋ฆฌ๊ฐ€ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿคญ

 

 

| ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ

- DB ์ปค๋„ฅ์…˜ ํ’€ ๊ฐ™์€ ์ž‘์—…์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ์ ์— ํ•„์š”ํ•œ ์—ฐ๊ฒฐ์„ ๋ฏธ๋ฆฌ ํ•ด๋‘๊ณ , ์ข…๋ฃŒ ์‹œ์ ์— ํ•œ ๋ฒˆ์— ์ข…๋ฃŒํ•˜๋Š” ๊ฒŒ ๋‚ซ๋‹ค.

   - ์Šคํ”„๋ง์—์„œ๋Š” ์ด๋Ÿฐ ์ดˆ๊ธฐํ™” ๋ฐ ์ข…๋ฃŒ ์ž‘์—…์„ ์–ด๋–ป๊ฒŒ ํ• ๊นŒ?

- ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ ์•Œ์•„๋ณด์ž.

 

[NetworkClient.java]

public class NetworkClient {
    private String url;

    public NetworkClient() {
        System.out.println("์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = " + url);
        connect();
        call("์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€");
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void connect() {
        System.out.println("connect: " + url);
    }

    public void call(String message) {
        System.out.println("call: " + url + " message: " + message);
    }

    public void disconnect() {
        System.out.println("close: " + url);
    }
}

 

โœ” Test

[BeanLifeCycleTest.java]

public class BeanLifeCycleTest {
    @Test
    public void lifeCycleTest() throws Exception {
        ConfigurableApplicationContext ac
                = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
        NetworkClient networkClient = ac.getBean(NetworkClient.class);
        ac.close(); // ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ข…๋ฃŒ
    }

    @Configuration
    static class LifeCycleConfig {
        @Bean
        public NetworkClient networkClient() {
            NetworkClient networkClient = new NetworkClient();
            networkClient.setUrl("http://hi.dev");
            return networkClient;
        }
    }
}

โœ” ์‹คํ–‰ ๊ฒฐ๊ณผ

์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = null
connect: null
call: null message: ์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€

 

- ๋ถ„๋ช… ๊ธฐ๋Œ€ํ•œ ๊ฑด setUrl์„ ํ†ตํ•ด ๋„ฃ์–ด์ง„ url ๊ฐ’์ด ๋‚˜์™€์•ผ ํ•˜๋Š”๋ฐ, null์ด ์ฐํžŒ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

- ์ด๋Š” ๋‹น์—ฐํ•˜๋‹ค. ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋‹จ๊ณ„์—์„œ๋Š” url์ด ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์šฐ๋ฆฌ๋Š” ์ƒ์„ฑ๋œ ์ดํ›„ ์ˆ˜์ •์ž๋กœ url์„ ์ฃผ์ž…ํ•˜์˜€๋‹ค.

url์„ ๋‹ด์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๊ณ  ์‹ถ๋‹ค๋ฉด ์™ธ๋ถ€์—์„œ networkClient.connect() ํ˜น์€ .call()์„ ํ˜ธ์ถœํ•ด์•ผ ์ฐํžˆ๊ฒŒ ๋œ๋‹ค.

 

๐Ÿšฉ ์‚ฌ์‹ค, ์˜ˆ์ œ์—์„œ setUrl()์„ ํ•˜๋Š” ๊ฒŒ ๊ณผ์—ฐ '์˜์กด๊ด€๊ณ„ ์ฃผ์ž…'์˜ ๊ด€์ ์—์„œ ๋ณผ ์ˆ˜ ์žˆ์„๊นŒ... ๋ผ๋Š” ์˜๋ฌธ์ด ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ '์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค' ๋ผ๋Š” ๊ด€์ ์—์„œ ๋ณด๋ฉด, url์„ ์™ธ๋ถ€๋กœ๋ถ€ํ„ฐ ์ฃผ์ž…๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, DI๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ถ๊ทน์ ์ธ ์ด์œ ๋Š” '์ถ”์ƒํ™”๋œ ๊ฒƒ์— ์˜์กด'ํ•˜์—ฌ '๊ฒฐํ•ฉ๋„'๋ฅผ ๋‚ฎ์ถ”๊ธฐ ์œ„ํ•จ์ด๋‹ค.

์œ„ ์˜ˆ์ œ์—์„œ setUrl()์„ ์ง„ํ–‰ํ•  ๋•Œ url์˜ ํƒ€์ž…์€ String์ด์–ด์„œ ๋ณ„๋„์˜ ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ˜๋‹ค๋Š” ๊ด€์ ์—์„œ ๋ณด๋ฉด ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด๋ผ๊ณ  ๋ณด๊ธฐ๋Š” ์–ด๋ ต๋‹ค. (์ด ๋ถ€๋ถ„ ์ฐพ์•„๋ณด๋ฉด์„œ ๊ฐœ์ธ์ ์œผ๋กœ DI์— ๋Œ€ํ•ด ๋‹ค์‹œ ์ƒ๊ฐํ•ด๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.)

 

 

โญ ์Šคํ”„๋ง ๋นˆ์€ ๊ฐ์ฒด ์ƒ์„ฑ -> ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ์ˆœ์œผ๋กœ ์ผ์–ด๋‚œ๋‹ค.

- ์ฆ‰, ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ๋๋‚˜์•ผ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐํ™”๋„ ๊ทธ ์ดํ›„์— ์ง„ํ–‰๋˜์–ด์•ผ ํ•œ๋‹ค.

- ์Šคํ”„๋ง์€ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ์™„๋ฃŒ ์‹œ, ์Šคํ”„๋ง ๋นˆ์—๊ฒŒ ์ฝœ๋ฐฑ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™” ์‹œ์ ์„ ์•Œ๋ ค์ฃผ๋ฉฐ, ์†Œ๋ฉธ ์ „์—๋„ ์†Œ๋ฉธ ์ฝœ๋ฐฑ์„ ๋‚ ๋ฆฐ๋‹ค.   

- InitializingBean, DisposableBean Interface 

- ์„ค์ • ์ •๋ณด์— ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ, ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์ง€์ •   

- @PostConstruct, @PreDestroy

 

์ฆ‰, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๊ฐ€์ง„๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿšฉ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ -> ์Šคํ”„๋ง ๋นˆ ์ƒ์„ฑ -> ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… -> ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ -> (์‹ค์ œ ์‚ฌ์šฉ) -> ์†Œ๋ฉธ ์ „ ์ฝœ๋ฐฑ -> ์Šคํ”„๋ง ์ข…๋ฃŒ

 

- โญ ๋‹จ,  ์ƒ์„ฑ์ž ์ฃผ์ž…์—์„œ๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์Šคํ”„๋ง ๋นˆ์ด ํ•จ๊ป˜ ๋“ค์–ด์™€์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ๋™์‹œ์— ์ผ์–ด๋‚œ๋‹ค.

    - ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ์ƒ์„ฑ์ž์— ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด, ํ•ด๋‹น ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ์Šคํ”„๋ง ๋นˆ์ด ๋“ค์–ด์™€์•ผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ. 

 

- ์ฐธ๊ณ ๋กœ, ์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ๋„ ์ƒ์„ฑ์ž ๋‚ด๋ถ€์—์„œ ์ดˆ๊ธฐํ™”๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฑด ๋ณ„๋กœ ์ข‹์ง€ ์•Š๋‹ค.

์ƒ์„ฑ์ž๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋”ฐ๋กœ ๋‚˜๋ˆ„์–ด์•ผ ์œ ์ง€๋ณด์ˆ˜ ์‹œ ๋” ๋‚ซ๋‹ค. (๊ฐ„๋‹จํ•œ ์ž‘์—…์ด๋ผ๋ฉด ์ƒ์„ฑ์ž ๋‚ด์—์„œ ํ•ด๋„ ๋˜๊ฒ ์ง€๋งŒ)


| ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ - InitializingBean, DisposableBean

- ์œ„์—์„œ ์‚ฌ์šฉํ•˜์˜€๋˜ NetworkClient ์˜ˆ์ œ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด์ž.

[NetworkClient.java]

public class NetworkClient implements InitializingBean, DisposableBean {
    private String url;

    public NetworkClient() {
        System.out.println("์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = " + url);
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void connect() {
        System.out.println("connect: " + url);
    }

    public void call(String message) {
        System.out.println("call: " + url + " message: " + message);
    }

    public void disconnect() {
        System.out.println("close: " + url);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        connect();
        call("์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€");
    }

    @Override
    public void destroy() throws Exception {
        disconnect();
    }
}

- InitializingBean, DisposableBean ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ afterPropertiesSet(), destroy() ํ•จ์ˆ˜๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•˜์˜€๋‹ค.

- ๊ธฐ์กด์— ์ƒ์„ฑ์ž์—์„œ ์ง„ํ–‰ํ•˜์˜€๋˜ connect, call ์ž‘์—…์„ afterPropertiesSet()์—์„œ ์ง„ํ–‰ํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

- ๊ฐ๊ฐ์€ ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ์„ ์ง€์›ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค!

 

โœ” ์‹คํ–‰ ๊ฒฐ๊ณผ

์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = null
connect: http://hi.dev
call: http://hi.dev message: ์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€
17:31:45.756 [Test worker] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1cdc4c27, started on Sun Aug 07 17:31:45 KST 2022
close: http://hi.dev

- ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์„ฑ๊ณต์ ์œผ๋กœ url์ด ์ž˜ ๋“ค์–ด๊ฐ„ ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

- ์ด๋Š” ๊ฐ’ ์ฃผ์ž… ์ดํ›„(setUrl) ๊ฐ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ์†Œ๋ฉธ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

- ๋‹จ, ์œ„ ๋ฐฉ๋ฒ•์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์Šคํ”„๋ง ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๋ฉฐ, ์ดˆ๊ธฐํ™”/์†Œ๋ฉธ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์˜ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

    - ์‚ฌ์‹ค์ƒ, ์œ„ ๋ฐฉ๋ฒ•์€ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๋ด๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.

 

๐Ÿšฉ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ข…์†์ ์ด๋ฉด ๋ฌด์—‡์ด ์•ˆ ์ข‹์„๊นŒ?

- ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด JVM์— ์˜ํ•ด์„œ .class -> .java๋กœ ๋ณ€๊ฒฝ์ด ๋˜๋Š”๋ฐ, .class์˜ ๊ฒฝ์šฐ ์ปดํŒŒ์ผ์ด ๋˜์–ด๋ฒ„๋ฆฐ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜์ •์ด ์–ด๋ ต๋‹ค.

๊ฐœ๋ฐœ์ž์˜ ์ž…์žฅ์—์„œ๋Š” ์ž‘์„ฑํ•œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€๋งŒ, ์‹ค์ œ๋กœ ํ”„๋กœ๊ทธ๋žจ์ด ๋™์ž‘ํ•  ๋•Œ๋Š” ์†Œ์Šค์ฝ”๋“œ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š”๋ฐ,

์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ด๋ฏธ .class๋กœ ์ปดํŒŒ์ผ์ด ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋‹ค.

 


| ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ - ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ ์ง€์ •

- ๋นˆ ๋“ฑ๋ก ์‹œ ์„ค์ • ์ •๋ณด์— initMethod, destroyMethod๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์‹œ ์˜ˆ์ œ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด์ž.

[NetworkClient.java]

public class NetworkClient {
    private String url;

    public NetworkClient() {
        System.out.println("์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = " + url);
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void connect() {
        System.out.println("connect: " + url);
    }

    public void call(String message) {
        System.out.println("call: " + url + " message: " + message);
    }

    public void disconnect() {
        System.out.println("close: " + url);
    }

    public void init() {
        System.out.println("NetworkClient.init");
        connect();
        call("์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€");
    }

    public void close() {
        System.out.println("NetworkClient.close");
        disconnect();
    }
}

[BeanLifeCycleTest.java]

public class BeanLifeCycleTest {
    @Test
    public void lifeCycleTest() throws Exception {
        ConfigurableApplicationContext ac
                = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
        NetworkClient networkClient = ac.getBean(NetworkClient.class);
        ac.close(); // ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ข…๋ฃŒ
    }

    @Configuration
    static class LifeCycleConfig {
        @Bean(initMethod = "init", destroyMethod = "close")
        public NetworkClient networkClient() {
            NetworkClient networkClient = new NetworkClient();
            networkClient.setUrl("http://hi.dev");
            return networkClient;
        }
    }
}

- @Bean์— initMethod์™€ destroyMethod๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค. ์ฐธ๊ณ ๋กœ, ์ด๋ฆ„์„ ์ž˜๋ชป ์ž…๋ ฅํ•˜๋ฉด ์ปดํŒŒ์ผ ์‹œ์ ์— ์—๋Ÿฌ๋‚œ๋‹ค. (์‹ ๊ธฐ...!)

 

โœ” ์‹คํ–‰ ๊ฒฐ๊ณผ

์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = null
NetworkClient.init
connect: http://hi.dev
call: http://hi.dev message: ์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€
17:53:36.244 [Test worker] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1cdc4c27, started on Sun Aug 07 17:53:35 KST 2022
NetworkClient.close
close: http://hi.dev

- ๊ฒฐ๊ณผ๊ฐ€ ์ž˜ ๋‚˜์˜ค๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ๋˜๋ฉฐ, ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค!

- ํŠนํžˆ, destroyMethod์˜ ๊ฒฝ์šฐ, default ๊ฐ’์ด (inferred)์ด๊ธฐ ๋•Œ๋ฌธ์— close(), shutdown()์ด๋ผ๋Š” ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ž๋™ ํ˜ธ์ถœํ•œ๋‹ค.

    - ๊ทธ๋ž˜์„œ ์œ„ ์˜ˆ์ œ์—์„œ๋Š” ๋”ฐ๋กœ destroyMethod๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์•„๋„ ์ž˜ ๋™์ž‘ํ•œ๋‹ค :D

 

๐Ÿšฉ ์ถ”๊ฐ€์ ์œผ๋กœ, ์œ„ ๋ฐฉ๋ฒ•์€ @Bean์—์„œ๋งŒ ์ ์šฉ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž๋™ ๋“ฑ๋กํ•˜๋Š” @Component์—์„œ๋Š” ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ทธ๋ž˜์„œ ๋ณดํ†ต ์„ธ ๋ฒˆ์งธ๋กœ ๋‚˜์˜ค๋Š” ๋ฐฉ๋ฒ•์„ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค :)

 


| ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ - @PostConstruct, @PreDestroy

- ๊ฐœ์ธ์ ์œผ๋กœ ๊ฐ€์žฅ ์„ ํ˜ธํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์•„๋งˆ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š์„๊นŒ...

[NetworkClient.java]

public class NetworkClient {
    private String url;

    public NetworkClient() {
        System.out.println("์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = " + url);
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void connect() {
        System.out.println("connect: " + url);
    }

    public void call(String message) {
        System.out.println("call: " + url + " message: " + message);
    }

    public void disconnect() {
        System.out.println("close: " + url);
    }

    @PostConstruct
    public void init() {
        System.out.println("NetworkClient.init");
        connect();
        call("์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€");
    }

    @PreDestroy
    public void close() {
        System.out.println("NetworkClient.close");
        disconnect();
    }
}

- ๋‹ค์Œ๊ณผ ๊ฐ™์ด @PostConstruct, @PreDestroy๋ฅผ ๋ถ™์—ฌ์ฃผ๋ฉด ๋œ๋‹ค.

- ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ @Bean๋„ ์›๋ž˜๋Œ€๋กœ ๋Œ๋ ค๋†“์ž. ์ž˜ ๋Œ์•„๊ฐ„๋‹ค.

 

- ์œ„ ๋ฐฉ๋ฒ•์˜ ๊ฒฝ์šฐ ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์€ ์ž๋ฐ” ํ‘œ์ค€์ด๊ธฐ ๋•Œ๋ฌธ์— ์Šคํ”„๋ง์— ์ข…์†์ ์ด์ง€ ์•Š๋‹ค๋Š” ํŠน์ง•์ด ์žˆ๋‹ค.

- ๊ทธ๋Ÿฌ๋‚˜, ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋Š” ์ ์šฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— (๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์œผ๋‹ˆ๊นŒ)

๊ทธ๋•Œ๋Š” @Bean์˜ initMethod๋ฅผ ์‚ฌ์šฉํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 


| ๋นˆ ์Šค์ฝ”ํ”„

- ์Šคํ”„๋ง ๋นˆ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€๋œ๋‹ค. ์ด๋Š” ์‹ฑ๊ธ€ํ†ค ์Šค์ฝ”ํ”„์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๐Ÿšฉ ์‹ฑ๊ธ€ํ†ค์ด๊ธฐ ๋•Œ๋ฌธ์— ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ•ญ์ƒ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ์Šคํ”„๋ง ๋นˆ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

- ์‹ฑ๊ธ€ํ†ค ์™ธ์—๋„ ๋‹ค์–‘ํ•œ ์Šค์ฝ”ํ”„๊ฐ€ ์กด์žฌํ•œ๋‹ค.

- ์‹ฑ๊ธ€ํ†ค: ๊ธฐ๋ณธ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€

- ํ”„๋กœํ† ํƒ€์ž…: ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ ์ƒ์„ฑ ๋ฐ ์˜์กด๊ด€๊ณ„๊นŒ์ง€๋งŒ ๊ด€์—ฌํ•˜๊ณ  ๊ด€๋ฆฌ X, ๋งค์šฐ ์งง๋‹ค

- ์›น (request) : ์›น ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐˆ ๋•Œ๊นŒ์ง€

- ์›น (session) : ์›น ์„ธ์…˜์ด ์ƒ์„ฑ๋˜๊ณ  ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€

- ์›น (application) : ์„œ๋ธ”๋ฆฟ ์ปจํ…์ŠคํŠธ์™€ ๊ฐ™์€ ๋ฒ”์œ„ 

 

- ์Šค์ฝ”ํ”„๋Š” @Scope("prototype")๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ง€์ • ๊ฐ€๋Šฅํ•˜๋‹ค.

 


| ๋นˆ ์Šค์ฝ”ํ”„ - ํ”„๋กœํ† ํƒ€์ž… ์Šค์ฝ”ํ”„

ํ”„๋กœํ† ํƒ€์ž… ์Šค์ฝ”ํ”„๋ฅผ ์กฐํšŒํ•˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•ญ์ƒ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค.

๋งŒ์•ฝ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ”„๋กœํ† ํƒ€์ž… ์Šค์ฝ”ํ”„ ๋นˆ์„ ์š”์ฒญํ•˜๋ฉด, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ํ•ด๋‹น ์‹œ์ ์— ํ”„๋กœํ† ํƒ€์ž… ๋นˆ ์ƒ์„ฑ + DI๊นŒ์ง€ ์ง„ํ–‰ํ•œ๋‹ค.

์ดํ›„, ์ƒ์„ฑํ•œ ๋นˆ์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ๋Š” ๋” ์ด์ƒ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์ € ๊ณผ์ •์„ ์ง„ํ–‰ํ•˜๋‹ˆ๊นŒ.

 

โญ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ๋นˆ ์ƒ์„ฑ, ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…, ์ดˆ๊ธฐํ™”๊นŒ์ง€๋งŒ ๊ด€์—ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— @PreDetroy ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค!

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ -> ์Šคํ”„๋ง ๋นˆ ์ƒ์„ฑ -> ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… -> ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ -> (์‹ค์ œ ์‚ฌ์šฉ) -> ์†Œ๋ฉธ ์ „ ์ฝœ๋ฐฑ -> ์Šคํ”„๋ง ์ข…๋ฃŒ

 

โœ” Test

[PrototypeTest.java]

public class PrototypeTest {
    @Test
    public void prototypeBeanFind() throws Exception {
        AnnotationConfigApplicationContext ac
                = new AnnotationConfigApplicationContext(PrototypeBean.class);
        System.out.println("find bean 1");
        PrototypeBean bean1 = ac.getBean(PrototypeBean.class);
        System.out.println("find bean 2");
        PrototypeBean bean2 = ac.getBean(PrototypeBean.class);

        System.out.println("bean1 = " + bean1);
        System.out.println("bean2 = " + bean2);

        assertThat(bean1).isNotSameAs(bean2);
        ac.close();
    }

    @Scope("prototype")
    static class PrototypeBean {
        @PostConstruct
        public void init() {
            System.out.println("PrototypeBean.init");
        }

        @PreDestroy
        public void destroy() {
            System.out.println("PrototypeBean.destroy");
        }
    }
}

โœ” ์‹คํ–‰ ๊ฒฐ๊ณผ

find bean 1
PrototypeBean.init
find bean 2
PrototypeBean.init
bean1 = study.springstudy.lifecycle.PrototypeTest$PrototypeBean@293bb8a5
bean2 = study.springstudy.lifecycle.PrototypeTest$PrototypeBean@2416a51
18:36:32.993 [Test worker] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1cdc4c27, started on Sun Aug 07 18:36:32 KST 2022

์—ฌ๊ธฐ์„œ ์•Œ ์ˆ˜ ์žˆ๋Š” ์‚ฌ์‹ค 3๊ฐ€์ง€!

1) @PostConstruct๋Š” ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค. ์ฆ‰, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋นˆ์„ ์กฐํšŒํ•  ๋•Œ ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ๊นŒ์ง€ ์‹คํ–‰๋œ๋‹ค.

2) ์กฐํšŒ ์‹œ ๊ฐ๊ฐ ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์กฐํšŒ๋œ ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ณ„์† ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑํ•จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

3) @PreDestroy๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์•˜๋‹ค. ์ดˆ๊ธฐํ™”๊นŒ์ง€๋งŒ ๊ด€์—ฌํ•˜๋‹ˆ๊นŒ ๊ทธ ์ดํ›„๋Š” ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค.

 

๊ทธ๋ž˜์„œ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ง์ ‘ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค. 

๋ฌผ๋ก , ์ข…๋ฃŒํ•˜์ง€ ์•Š๋”๋ผ๋„ ์–ด์จŒ๊ฑฐ๋‚˜ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— GC์— ์˜ํ•ด์„œ Heap ์˜์—ญ ์ •๋ฆฌ ์‹œ ํ•จ๊ป˜ ์ œ๊ฑฐ๋œ๋‹ค.

 

๐Ÿšฉ ํ”„๋กœํ† ํƒ€์ž…์€ ์กฐํšŒํ•  ๋•Œ ์‹คํ–‰๋œ๋‹ค๊ณ  ํ•˜๋Š”๋ฐ, ๊ทธ๋Ÿฌ๋ฉด ๊ฐ€์žฅ ์ฒซ ์ค„์˜ new Annotation~(PrototypeBean.class)๋Š” ๋ญ˜ ํ•˜๋Š” ๊ฑธ๊นŒ?

์‹ฑ๊ธ€ํ†ค์ด๋“ , ํ”„๋กœํ† ํƒ€์ž…์ด๋“  ๊ธฐ๋ณธ์ ์œผ๋กœ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ๊ฐ€์žฅ ์ฒซ ์ค„์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธด ์„ค์ • ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋•Œ, ํ•ด๋‹น ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋นˆ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, (์—ฌ๊ธฐ์„œ init ๊ฐ™์€ ์ •๋ณด๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค๊ณ  ์•Œ๊ณ  ์žˆ๋‹ค) ํ”„๋กœํ† ํƒ€์ž…์˜ ๊ฒฝ์šฐ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊นŒ์ง€๋งŒ ์ƒ์„ฑ๋˜๊ณ  ์‹ค์ œ ๋นˆ ์ƒ์„ฑ๊นŒ์ง€๋Š” ์ง„ํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค. ์ƒ์„ฑ์€ ์กฐํšŒํ–ˆ์„ ๋•Œ!

 


| ํ”„๋กœํ† ํƒ€์ž… ๋นˆ๊ณผ ์‹ฑ๊ธ€ํ†ค ๋นˆ์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด?

โœ” ๋‹จ์ˆœ ํ”„๋กœํ† ํƒ€์ž… ์‚ฌ์šฉ ์‹œ ์š”์ฒญ ๊ณผ์ • 

- ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์— count๋ผ๋Š” ๋นˆ๊ณผ, count ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๋Š” addCount()๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

 

- ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์š”์ฒญํ•œ๋‹ค.

- ์ปจํ…Œ์ด๋„ˆ๋Š” ์ƒˆ๋กญ๊ฒŒ ๋นˆ์„ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋•Œ, ๋นˆ์˜ count ํ•„๋“œ ๊ฐ’์€ 0์ด๋‹ค.

- ์กฐํšŒํ•œ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ(A)์˜ addCount()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ count ํ•„๋“œ ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค. 0->1

- ๊ฒฐ๊ณผ์ ์œผ๋กœ A์˜ count ๊ฐ’์€ 1์ด ๋œ๋‹ค.

 

- ์ดํ›„, ๋˜ ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ปจํ…Œ์ด๋„ˆ์— ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์š”์ฒญํ•œ๋‹ค.

- ์ปจํ…Œ์ด๋„ˆ๋Š” ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ƒˆ๋กญ๊ฒŒ ๋นˆ์„ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค. count ํ•„๋“œ ๊ฐ’์€ 0์ด๋‹ค.

- ์กฐํšŒํ•œ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ(B)์˜ addCount()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ count ํ•„๋“œ ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค. 0->1

- ๊ฒฐ๊ณผ์ ์œผ๋กœ B์˜ count ๊ฐ’์€ 1์ด ๋œ๋‹ค.

 

- ์—ฌ๊ธฐ๊นŒ์ง€๋งŒ ๋ณด๋ฉด ๋‹น์—ฐํ•œ ๊ฒฐ๊ณผ์ด๋‹ค. ์ด๋ฒˆ์—๋Š” ์‹ฑ๊ธ€ํ†ค๊ณผ ํ”„๋กœํ† ํƒ€์ž…์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด๋ณด์ž.

[SingletonWithPrototypeTest1.java - PrototypeBean]

@Scope("prototype")
static class PrototypeBean {
    private int count = 0;
    public void addCount() {
        count++;
    }
    public int getCount() {
        return count;
    }
    @PostConstruct
    public void init() {
        System.out.println("PrototypeBean.init " + this);
    }
    @PreDestroy
    public void destroy() {
        System.out.println("PrototypeBean.destroy");
    }
}

- ํ”„๋กœํ† ํƒ€์ž… ์Šค์ฝ”ํ”„๋ฅผ ๊ฐ€์ง„ ๋นˆ์ด๋‹ค. ๋‚ด๋ถ€์— count๋ผ๋Š” ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

 

[SingletonWithPrototypeTest1.java - ClientBean]

static class ClientBean {
    private final PrototypeBean prototypeBean;

    @Autowired
    public ClientBean(PrototypeBean prototypeBean) {
        this.prototypeBean = prototypeBean;
    }

    public int logic() {
        // DI์— ์˜ํ•ด ClientBean ์ƒ์„ฑ ์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ PrototypeBean ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— .addCount() ๊ฐ€๋Šฅ
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}

- ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹ฑ๊ธ€ํ†ค ๋นˆ์ด๋‹ค. 

- ์ด๋•Œ, ์œ„์—์„œ ์„ ์–ธํ•œ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑ์ž ์ฃผ์ž…ํ•˜์˜€๋‹ค. logic()์„ ํ†ตํ•ด count ๊ฐ’์„ ๋Š˜๋ฆฌ๊ณ  ํ•ด๋‹น ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์˜€๋‹ค.

๐Ÿšฉ ์ฐธ๊ณ ๋กœ, ์ด๋Ÿฐ ์‹์œผ๋กœ ์„ ์–ธํ•˜๋ฉด ๋‚ด๋ถ€ ํ”„๋กœํ† ํƒ€์ž… ์Šค์ฝ”ํ”„ ๊ฐ์ฒด๋Š” ์ง์ ‘ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•ด์•ผ ํ•œ๋‹ค. (๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฌธ์ œ)

 

[SingletonWithPrototypeTest1.java - singletonClientUsePrototype()]

@Test
void singletonClientUsePrototype() {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);

    ClientBean clientBean1 = ac.getBean(ClientBean.class);
    int count1 = clientBean1.logic();
    assertThat(count1).isEqualTo(1);

    ClientBean clientBean2 = ac.getBean(ClientBean.class);
    int count2 = clientBean2.logic();
    assertThat(count2).isEqualTo(2);
}

- ์‹ค์ œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์ด๋‹ค. ์œ„์—์„œ ์‚ฌ์šฉํ•œ 2๊ฐœ์˜ ๋นˆ์„ ์„ค์ • ํŒŒ์ผ๋กœ ๋‘์—ˆ์œผ๋ฉฐ ๊ฐ๊ฐ์„ ์กฐํšŒํ•˜์˜€๋‹ค.

 

โœ” ์š”์ฒญ ๊ณผ์ •

1. ClientBean์€ ์‹ฑ๊ธ€ํ†ค์ด๊ธฐ ๋•Œ๋ฌธ์—, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์ƒ์„ฑ ์‹œ์ ์— ํ•จ๊ป˜ ์ƒ์„ฑ๋˜๊ณ  ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ์ง„ํ–‰๋œ๋‹ค.

- ์ด๋•Œ, ClientBean์€ ์ฃผ์ž… ์‹œ์ ์— ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์š”์ฒญํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ปจํ…Œ์ด๋„ˆ๋Š” ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

- ์ด๋•Œ, ํ”„๋กœ๋กœํƒ€์ž… ๋นˆ์˜ count ํ•„๋“œ ๊ฐ’์€ 0์ด๋‹ค.

2. ์ดํ›„, ClientBean์€ ์ƒ๋ช…์ฃผ๊ธฐ๊ฐ€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ ์ฐธ์กฐ๊ฐ’์„ ๋‚ด๋ถ€ ํ•„๋“œ์— ๋ณด๊ด€ํ•œ๋‹ค.

3. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ac.getBean()์„ ํ†ตํ•ด ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญ์„ ํ•˜๋ฉด, ์œ„์™€ ๋™์ผํ•œ ClientBean์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

4. clientBean1.logic()์„ ํ˜ธ์ถœํ•˜๋ฉด, ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ addCount()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ count๋ฅผ 0->1๋กœ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.

5. ์ดํ›„, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ac.getBean()์„ ํ†ตํ•ด ๋˜ ๋‹ค์‹œ ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญํ•˜๋ฉด ๋™์ผํ•œ clientBean์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

- ์ด๋•Œ, ๋‚ด๋ถ€์— ์กด์žฌํ•˜๋Š” ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์€ ๊ณผ๊ฑฐ์— ์ฃผ์ž…์ด ๋๋‚ฌ๋‹ค. ๋˜ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด์„œ ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

6, clientBean2.logic()์„ ํ˜ธ์ถœํ•˜๋ฉด, addCount๋กœ ์ธํ•ด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ count๋ฅผ 1->2๋กœ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.

 

์ฆ‰, ์œ„ ๊ณผ์ •์—์„œ ๋ฌธ์ œ๋Š” ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๋ ค๊ณ  ํ”„๋กœํ† ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฑด๋ฐ, ์‹ฑ๊ธ€ํ†ค ๋นˆ๊ณผ ํ•จ๊ป˜ ๊ณ„์† ์œ ์ง€๋˜๋Š” ๊ฒƒ์ด๋‹ค.

- ์ด๋Š”, ์‹ฑ๊ธ€ํ†ค ๋นˆ์˜ ์ƒ์„ฑ์ž ์ฃผ์ž… ์‹œ์ ์— ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ๋ฐ›์œผ๋ฉด์„œ ํ”„๋กœํ† ํƒ€์ž…์ด ์ƒˆ๋กœ ์ƒ๊ธฐ๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ฃผ์ž…์ด ์ข…๋ฃŒ๋œ ์ดํ›„์—๋Š” ๊ณ„์† ์œ ์ง€๋˜๋Š” ๊ฒƒ.

 


| ํ”„๋กœํ† ํƒ€์ž… ๋นˆ๊ณผ ์‹ฑ๊ธ€ํ†ค ๋นˆ์„ ํ˜ผ์šฉ - Provider ์ด์šฉํ•˜๊ธฐ

- ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

 

1. ์‹ฑ๊ธ€ํ†ค ๋นˆ์ด ํ”„๋กœํ† ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญํ•˜๊ธฐ.

[SingletonWithPrototypeTest1.java - ClientBean ์ˆ˜์ •]

static class ClientBean {
    @Autowired
    private ApplicationContext ac;

    public int logic() {
        PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}

- ac.getBean()์„ ์ด์šฉํ•˜๋ฉด ์กฐํšŒ ์‹œ ์ƒ์„ฑ + ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… + ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ๊นŒ์ง€ ๋™์ž‘ํ•˜๋‹ˆ๊นŒ ํ•ญ์ƒ ์ƒˆ๋กœ์šด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์ด ๋ฐ˜ํ™˜๋œ๋‹ค.

- ์ด๋Š”, ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ์ง„ํ–‰ํ•œ ๊ฒƒ์ด ์•„๋‹Œ ๋‚ด๋ถ€์—์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฐพ์€ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— DL (Dependency Lookup)์ด๋ผ๊ณ  ํ•œ๋‹ค.

- ๊ทธ๋Ÿฌ๋‚˜, ์ด ์ฝ”๋“œ๋Š” ์ปจํ…Œ์ด๋„ˆ์— ์ข…์†์ ์ด๊ณ  ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ต๋‹ค. ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์ž!

 

[SingletonWithPrototypeTest1.java - ClientBean ์ˆ˜์ •]

static class ClientBean {
    @Autowired
    private ObjectProvider<PrototypeBean> provider;

    public int logic() {
        PrototypeBean prototypeBean = provider.getObject();
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}

- ObjectProvider๋ฅผ ์‚ฌ์šฉํ•˜์ž! (ํ˜น์€ ObjectFactory๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค! ๊ทผ๋ฐ Provider๋Š” ์กฐ๊ธˆ ๋” ๊ธฐ๋Šฅ์ด ๋งŽ๋‹ค๊ณ  ํ•œ๋‹ค.)

- getObject()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋นˆ์„ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค. (DL ๊ธฐ๋Šฅ)

- DL ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์ฃผ๋Š”, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€์‹  ์กฐํšŒํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ... ์ •๋„๋ผ๊ณ  ์ƒ๊ฐํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

๐Ÿšฉ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋นˆ ํŒฉํ† ๋ฆฌ์—์„œ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ƒ์„ฑ๋œ ๋นˆ์„ ์ฐพ์•„ ๋ฐ˜ํ™˜ํ•˜๋Š” DL ๊ธฐ๋Šฅ์€ Provider๊ฐ€ ์ง„ํ–‰.

.getObject()๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด, ๋นˆ์ด ์ƒ์„ฑ๋˜๊ณ , ์ดํ›„ Provider๊ฐ€ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•œ๋‹ค.

 

static class ClientBean {
    @Autowired
    private Provider<PrototypeBean> provider;

    public int logic() {
        PrototypeBean prototypeBean = provider.get();
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}

- ์•„๋‹ˆ๋ฉด, ์ž๋ฐ” ํ‘œ์ค€์—์„œ ์ œ๊ณตํ•˜๋Š” Provider๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. (javax.inject.Provider)

-> build.grade์— javax.inject:javax.inject:1๋ฅผ import ํ•ด์ค˜์•ผ ํ•จ! 

- ์ž๋ฐ” ํ‘œ์ค€์ด๊ธฐ ๋•Œ๋ฌธ์— ์Šคํ”„๋ง์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ DL ์ •๋„์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

 

- Provider๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋‘ ํƒ€์ž…์œผ๋กœ ๋นˆ์„ ์กฐํšŒํ•œ๋‹ค๋Š” ํŠน์ง•์ด ์žˆ๋‹ค. ์ด๋ฆ„ ์กฐํšŒ ๋“ฑ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ApplicationContext ์‚ฌ์šฉํ•˜๊ธฐ.

 

๐Ÿšฉ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์ด ๊ตณ์ด ํ•„์š”ํ• ๊นŒ? ๋ผ๋Š” ์˜๋ฌธ

- ์ˆœ์ˆ˜ ์ž๋ฐ”์ฝ”๋“œ๋กœ ๊ณ„์† new ์ƒ์„ฑํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹๊นŒ? ์‹ถ์„ ์ˆ˜๋„ ์žˆ๋‹ค.

- ๋‹ค๋งŒ, ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์‚ฌ์šฉํ•˜๋ฉด @Autowired๋ฅผ ์ง€์›๋ฐ›์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ DI๊ฐ€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฌผ๋ก , ์ž๋ฐ” ์ฝ”๋“œ๋กœ๋„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ œ์–ด๋ฅผ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋„˜๊ธด๋‹ค๋Š” ๊ฑด ๊ฐœ๋ฐœ์ž๋กœ์„œ ๋งค์šฐ ์ข‹์€ ์ ์ด๋‹ˆ๊นŒ.

 


| ์›น ์Šค์ฝ”ํ”„

- ์›น ํ™˜๊ฒฝ์—์„œ ๋™์ž‘ํ•˜๋Š” ์Šค์ฝ”ํ”„. ์Šคํ”„๋ง์ด ํ•ด๋‹น ์Šค์ฝ”ํ”„์˜ ์ข…๋ฃŒ ์‹œ์ ๊นŒ์ง€ ๊ด€๋ฆฌํ•œ๋‹ค.

- ๋Œ€ํ‘œ์ ์œผ๋กœ request ์Šค์ฝ”ํ”„์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

 

โœ” Request Scope

- HTTP ์š”์ฒญ ํ•˜๋‚˜๊ฐ€ ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐˆ ๋•Œ๊นŒ์ง€ ์œ ์ง€๋˜๋Š ์Šค์ฝ”ํ”„์ด๋‹ค. ๊ฐ HTTP ์š”์ฒญ๋งˆ๋‹ค ๋ณ„๋„์˜ ๋นˆ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๊ด€๋ฆฌ๋œ๋‹ค.

- ๋‚ด๋ถ€์˜ HTTP ์š”์ฒญ์€ sessionId ๋“ฑ์œผ๋กœ (๋ณ„๋„์˜ ์‹๋ณ„์ž ์ด์šฉ) ๋™์ผํ•œ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์ธ์ง€ ์„œ๋ฒ„ ๋‚ด์—์„œ ํŒ๋‹จํ•œ๋‹ค.

 

์˜ˆ์ œ๋ฅผ ์œ„ํ•ด build.gradle์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•˜์ž.

implementation 'org.springframework.boot:spring-boot-starter-web'

: ๋‚ด์žฅ ํ†ฐ์บฃ ์„œ๋ฒ„๋ฅผ ํ™œ์šฉํ•ด์„œ ์›น ์„œ๋ฒ„์™€ ์Šคํ”„๋ง์„ ํ•จ๊ป˜ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

: AnnotationConfigApplicationContext -> AnnotationConfigServletWebServerApplicationContext ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

 

 

- ์š”์ฒญ๋งˆ๋‹ค ๋นˆ ์ƒ์„ฑ๊ณผ ์ข…๋ฃŒ๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋กœ๊ฑฐ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์ž.

[MyLogger.java]

@Component
@Scope(value = "request") // request scope
public class MyLogger {
    private String uuid;
    private String requestURL;

    public void setRequestURL(String requestURL) {
        this.requestURL = requestURL;
    }

    public void log(String message) {
        System.out.println("[" + uuid + "]" + "[" + requestURL + "] " +
                message);
    }

    @PostConstruct
    public void init() {
        // ๋นˆ ์ƒ์„ฑ ์‹œ์ ์— UUID๋ฅผ ์ƒ์„ฑํ•˜์—ฌ HTTP ์š”์ฒญ์„ ๊ตฌ๋ถ„ํ•ด์ฃผ๊ธฐ
        uuid = UUID.randomUUID().toString();
        System.out.println("[" + uuid + "] request scope bean create:" + this);
    }

    @PreDestroy
    public void close() {
        // ๋นˆ ์†Œ๋ฉธ ์‹œ์ ์— ๋ฉ”์‹œ์ง€ ๋‚จ๊ธฐ๊ธฐ
        System.out.println("[" + uuid + "] request scope bean close:" + this);
    }
}

- ์ด๋Ÿฌ๋ฉด ๋กœ๊ทธ์— [UUID][requestURL] message ํ˜•ํƒœ๋กœ ์ฐํžˆ๊ฒŒ ๋œ๋‹ค.

 

๐Ÿšฉ request scope์˜ ๊ฒฝ์šฐ, "์›น ์š”์ฒญ์ด ๋“ค์–ด์™€์•ผ" ๋นˆ์ด ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ˆœํžˆ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ํ•˜๋ ค๊ณ  ํ•˜๋ฉด

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฐพ์•„์˜ฌ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ๋‚  ์ˆ˜๋ฐ–์— ์—†๋‹ค. ์ด๋Ÿด ๋•Œ ObjectProvider๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค!

 

 

[LogDemoInterceptor.java]

@RequiredArgsConstructor
public class LogDemoInterceptor implements HandlerInterceptor {
    private final ObjectProvider<MyLogger> provider;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        MyLogger myLogger = provider.getObject();
        String requestURL = request.getRequestURL().toString();
        myLogger.setRequestURL(requestURL);
        myLogger.log("controller test");
        return true;
    }
}

- ๊ฐ„๋‹จํ•œ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. HandlerInterceptor ์ธํ„ฐํŽ˜์ด์Šค์—์„œ preHandler ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

- ์ด๋Ÿฌ๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์š”์ฒญ์ด ๊ฐ€๊ธฐ ์ „์— ์‚ฌ์ „ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค!

 

[WebMvcConfig.java]

@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
    private final ObjectProvider<MyLogger> provider;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogDemoInterceptor(provider))
                .addPathPatterns("/log-demo");
    }
}

- WebMvcConfigurer๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋งŒ๋“ค์–ด์ค€ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. 

- ObjectProvider์˜ ๊ฒฝ์šฐ ์Šคํ”„๋ง์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฃผ์ž…ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ๋นˆ ๋“ฑ๋ก์„ ์ฒ˜๋ฆฌํ•ด์ค„ ํ•„์š”๋Š” ์—†๋‹ค.

 

[LogDemoService.java]

@Service
@RequiredArgsConstructor
public class LogDemoService {
    private final ObjectProvider<MyLogger> provider;

    public void logic(String id) {
        MyLogger myLogger = provider.getObject();
        myLogger.log("service id = " + id);
    }
}

- ๊ฐ„๋‹จํ•œ ์„œ๋น„์Šค ๊ณ„์ธต์„ ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋‹ค. @Service ๋‚ด์— @Component๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋นˆ ๋“ฑ๋ก์€ ์ž˜ ๋œ๋‹ค.

- ์„œ๋น„์Šค ๊ณ„์ธต์˜ ๊ฒฝ์šฐ ์›น๊ณผ ๊ด€๋ จ๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ์—†๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. (HttpServletRequest ๊ฐ™์€)

 

[LogDemoController.java]

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    private final LogDemoService logDemoService;

    @RequestMapping("/log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request) {
        logDemoService.logic("testId");
        return "OK";
    }
}

- ์ปจํŠธ๋กค๋Ÿฌ ๊ณ„์ธต์ด๋‹ค. /log-demo๋กœ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•ด์ฃผ์—ˆ์œผ๋ฉฐ (์ธํ„ฐ์…‰ํ„ฐ ๋“ฑ๋ก ์‹œ ๊ฒฝ๋กœ์™€ ์ผ์น˜ํ•˜๊ฒŒ) ๋‹จ์ˆœํžˆ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

์ดํ›„, ๋ธŒ๋ผ์šฐ์ €์—์„œ http://localhost:8080/log-demo๋ฅผ ์‹คํ–‰ํ•ด๋ณด๋ฉด...!

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์š”์ฒญ๋งˆ๋‹ค ๊ฒฐ๊ณผ๊ฐ€ ๋งค์šฐ ์ž˜ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค :D

- ObjectProvider ๋•๋ถ„์— .getObject()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ๊นŒ์ง€ Request Scope ๋นˆ์˜ ์ƒ์„ฑ์„ ์ง€์—ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

- .getObject()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ์—๋Š” ์ด๋ฏธ HTTP ์š”์ฒญ์ด ์ง„ํ–‰๋˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— request scope ๋นˆ์˜ ์ƒ์„ฑ์ด ์ •์ƒ ์ฒ˜๋ฆฌ๊ฐ€ ๋œ๋‹ค.

    - ์ฆ‰, ๊ฒฐ๊ณผ์ ์œผ๋กœ ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ .getObject๋ฅผ ํ†ตํ•ด์„œ MyLogger๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

 

๐Ÿšฉ ์ •ํ™•ํ•˜๊ฒŒ๋Š”, ์š”์ฒญ์ด ๋“ค์–ด์™€์„œ Request Scope์ด ํ•„์š”ํ•œ ์‹œ์ ์— ObjectProvider๋ฅผ ํ†ตํ•ด Request Scope ๋นˆ์„ ์ฐพ์•„์™€์„œ (DL)

๋งŒ์•ฝ ์žˆ์œผ๋ฉด ํ•ด๋‹น ๋นˆ์„, ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑํ•ด์„œ ๋ฆฌํ„ดํ•ด์ค€๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค!

 


| ์Šค์ฝ”ํ”„์— ํ”„๋ก์‹œ ์ ์šฉํ•˜๊ธฐ

[MyLogger.java]

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
    private String uuid;
    private String requestURL;

    public void setRequestURL(String requestURL) {
        this.requestURL = requestURL;
    }

    public void log(String message) {
        System.out.println("[" + uuid + "]" + "[" + requestURL + "] " +
                message);
    }

    @PostConstruct
    public void init() {
        uuid = UUID.randomUUID().toString();
        System.out.println("[" + uuid + "] request scope bean create:" + this);
    }

    @PreDestroy
    public void close() {
        System.out.println("[" + uuid + "] request scope bean close:" + this);
    }

}

- proxyMode๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค. ์ ์šฉ ๋Œ€์ƒ์ด ํด๋ž˜์Šค๋ฉด TARGET_CLASS๋ฅผ, ์ธํ„ฐํŽ˜์ด์Šค๋Š” INTERFACES๋ฅผ ์„ ํƒํ•œ๋‹ค.

- ์ด๋Ÿฌ๋ฉด MyLogger์— ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ , HTTP Request์™€ ์ƒ๊ด€์—†์ด ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž™์Šค๋ฅผ ๋ฏธ๋ฆฌ ๋นˆ์— ์ฃผ์ž…ํ•ด๋‘˜ ์ˆ˜ ์žˆ๋‹ค.

 

- ์ฝ”๋“œ๋„ ์ˆ˜์ •ํ•ด์ฃผ์ž.

[LogDemoInterceptor.java]

@RequiredArgsConstructor
public class LogDemoInterceptor implements HandlerInterceptor {
    private final MyLogger myLogger;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURL = request.getRequestURL().toString();
        myLogger.setRequestURL(requestURL);
        myLogger.log("controller test");
        return true;
    }
}

 

[LogDemoService.java]

@Service
@RequiredArgsConstructor
public class LogDemoService {
    private final MyLogger myLogger;

    public void logic(String id) {
        myLogger.log("service id = " + id);
    }
}

- ์‹คํ–‰ํ•ด๋ณด๋ฉด ์•„๊นŒ์™€ ๊ฐ™์ด ์ž˜ ๋™์ž‘ํ•œ๋‹ค.

- ๊ทธ๋ ‡๋‹ค๋ฉด, ์Šคํ”„๋ง ์‹œ์ž‘ ์‹œ myLogger๋Š” ๋ญ๊ฐ€ ์ฃผ์ž…๋œ ๊ฑธ๊นŒ...?

- ๋กœ๊ทธ๋ฅผ ์ฐ์–ด๋ณด๋ฉด, CGLIB๋กœ ์ธํ•œ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

CGLIB๋ฅผ ํ†ตํ•ด MyLogger๋ฅผ ์ƒ์†๋ฐ›์€ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

-> ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— "myLogger"๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋“ฑ๋กํ•˜๊ฒŒ ๋œ๋‹ค. DI ์‹œ์—๋„ ์ด ๊ฐ€์งœ ํ”„๋กœ์‹œ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค!

 

๐Ÿšฉ ์‹ค์ œ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด, ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ๋‚ด๋ถ€์—์„œ ์ง„์งœ ๋นˆ์„ ์š”์ฒญํ•˜๋Š” ์œ„์ž„ ๋กœ์ง์„ ํ˜ธ์ถœํ•˜๋ฉฐ,

ํด๋ผ์ด์–ธํŠธ๊ฐ€ myLogger.logic() ํ˜ธ์ถœ -> ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์‹ค์ œ ๊ฐ์ฒด์˜ myLogger.logic() ํ˜ธ์ถœ -> ์‹คํ–‰์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

- ์ด๋Š”, ์‹ค์ œ request scope์™€ ๊ด€๊ณ„์—†์ด ๊ทธ๋ƒฅ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด์ด๋ฉฐ, ์‹ฑ๊ธ€ํ†ค์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค. (๊ทธ๋Ÿฌ๋‚˜, ์‹ค์ œ ์‹ฑ๊ธ€ํ†ค์€ ์•„๋‹ˆ๋ผ๋Š” ๊ฑฐ!)

 

- ํ”„๋ก์‹œ ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด CGLIB๋ฅผ ํ™œ์šฉํ•œ ๋นˆ ๊ฐ์ฒด๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ์‹œ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์ง„์งœ ๊ฐ์ฒด๋ฅผ ๋งค๋ฒˆ ์ƒ์„ฑํ• ์ง€ ๋ง์ง€๋Š” ์ง„์งœ ๋นˆ์˜ ์Šค์ฝ”ํ”„์— ๋”ฐ๋ผ์„œ ๋‹ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์—, ์‹ฑ๊ธ€ํ†ค์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฒŒ ๋˜๋ฉด ์‹ฑ๊ธ€ํ†ค์ด ์•„๋‹Œ๋ฐ๋„ ๊ทธ๋ ‡๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฑฐ๋‹ˆ๊นŒ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉ ์‹œ ์ฃผ์˜ํ•  ๊ฒƒ.

 

โญ ์‹ค์ œ ๊ฐ์ฒด ์กฐํšŒ๋ฅผ ํ•„์š”ํ•œ ์‹œ์ ๊นŒ์ง€ ์ง€์—ฐ ์ฒ˜๋ฆฌํ•œ๋‹ค๋Š” ๊ฒŒ ํ•ต์‹ฌ์ด๋ฉฐ,

์• ๋…ธํ…Œ์ด์…˜ ์„ค์ • ๋ณ€๊ฒฝ๋งŒ์œผ๋กœ ์›๋ณธ ๊ฐ์ฒด๋ฅผ ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒŒ ๋‹คํ˜•์„ฑ, DI ์ปจํ…Œ์ด๋„ˆ์˜ ๊ฐ•์ ์ด๋‹ค.

 


 

์ด๋ ‡๊ฒŒ ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ๋ฅผ ์™„๊ฐ•ํ•˜์˜€๋‹ค! ๋‘ ๋ฒˆ์งธ ๋“ฃ๋Š” ๊ฑด๋ฐ๋„ ๊ต‰์žฅํžˆ ์ƒˆ๋กญ๊ณ ...

์•„์ง ๋ชจ๋ฅด๋Š” ๊ฒƒ์ด ํˆฌ์„ฑ์ด๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ๋” ์—ด์‹ฌํžˆ ๋“ค์–ด์•ผ๊ฒ ๋‹ค... ๐Ÿ˜ฅ๐Ÿ’ฆ

Comments