๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
โญ Personal_Study/Spring

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

by ํฌ์ŠคํŠธ์‰์ดํฌ 2023. 1. 10.

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

1. ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ ์‹œ์ž‘

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ํ’€, ๋„คํŠธ์›Œํฌ ์†Œ์ผ“ ๋“ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ์ ์— ํ•„์š”ํ•œ ์—ฐ๊ฒฐ์„ ๋ฏธ๋ฆฌ ํ•ด๋‘๊ณ , ์ข…๋ฃŒ ์‹œ์ ์— ์—ฐ๊ฒฐ์„ ๋ชจ๋‘ ์ข…๋ฃŒํ•˜๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋ ค๋ฉด ๊ฐ์ฒด์˜ ์ดˆ๊ธฐํ™”์™€ ์ข…๋ฃŒ ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค

์˜ˆ์ œ ์ฝ”๋“œ

// 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);
    }
}
// BeanLifeCycleTest.java

public class BeanLifeCycleTest {

    @Test
    public void lifeCycleTest() {
        ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
        NetworkClient client = ac.getBean(NetworkClient.class);
        ac.close();
    }

    @Configuration
    static class LifeCycleConfig {

        @Bean
        public NetworkClient networkClient() {
            NetworkClient networkClient = new NetworkClient();
            networkClient.setUrl("http://hellospring.dev");
            return networkClient;
        }
    }
}
// ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ

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

๊ฐ์ฒด ์ƒ์„ฑ ๋‹จ๊ณ„์—์„œ๋Š” url์ด ์—†์œผ๋ฏ€๋กœ url ์ •๋ณด๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค

url์€ ๊ฐ์ฒด ์ƒ์„ฑ ์ดํ›„ ์ˆ˜์žฅ์ž ์ฃผ์ž…์„ ํ†ตํ•ด setUrl()์ด ํ˜ธ์ถœ๋˜์–ด์•ผ ์กด์žฌํ•˜๊ฒŒ ๋œ๋‹ค.

์Šคํ”„๋ง ๋นˆ ์ด๋ฒคํŠธ ๋ผ์ดํ”„์‚ฌ์ดํด

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

๊ฐ์ฒด๋ฅผ ๋จผ์ € ์ƒ์„ฑํ•˜๊ณ  ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ๋๋‚œ ๋‹ค์Œ์— ์ดˆ๊ธฐํ™”๊ฐ€ ์ด๋ฃจ์–ด์ง„๋‹ค

์Šคํ”„๋ง์—์„œ ์ƒ์„ฑ/์†Œ๋ฉธ ์ฝœ๋ฐฑ ๋ฉ”์„œ๋“œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์ค€๋‹ค

์ฐธ๊ณ : ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์ดˆ๊ธฐํ™” ๋ถ„๋ฆฌ

์ƒ์„ฑ์ž๋Š” ํ•„์ˆ˜ ์ •๋ณด(ํŒŒ๋ผ๋ฏธํ„ฐ)๋ฅผ ๋ฐ›๊ณ  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•ด์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ

๋ฐ˜๋ฉด, ์ดˆ๊ธฐํ™”๋Š” ์ƒ์„ฑ๋œ ๊ฐ’๋“ค์„ ํ™œ์šฉํ•ด ์™ธ๋ถ€ ์ปค๋„ฅ์…˜์„ ์—ฐ๊ฒฐํ•˜๋Š” ๋“ฑ ๋ฌด๊ฑฐ์šด ๋™์ž‘ ์ˆ˜ํ–‰

โœ” ๋”ฐ๋ผ์„œ ์ƒ์„ฑ์ž ์•ˆ์—์„œ ๋ฌด๊ฑฐ์šด ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ํ•จ๊ป˜ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ƒ์„ฑ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€ ๋ณด์ˆ˜ ๊ด€์ ์—์„œ ๋ฐ”๋žŒ์ง

์ดˆ๊ธฐํ™” ์ž‘์—…์ด ๊ฐ€๋ณ๊ณ  ๋‹จ์ˆœํ•œ ๊ฒฝ์šฐ์—๋Š” ์ƒ์„ฑ์ž์—์„œ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

์Šคํ”„๋ง์˜ 3๊ฐ€์ง€ ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ

  1. ์ธํ„ฐํŽ˜์ด์Šค(InitializingBean, DisposableBean)
  2. ์„ค์ • ์ •๋ณด์— ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ, ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์ง€์ •
  3. @PostConstruct, @PreDestroy ์• ๋…ธํ…Œ์ด์…˜ ์ง€์›

2. ์ธํ„ฐํŽ˜์ด์Šค(InitializingBean, DisposableBean)

์ ์šฉ ์ฝ”๋“œ

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 ์€ afterPropertiesSet() ๋ฉ”์„œ๋“œ๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ์ง€์›ํ•œ๋‹ค.

DisposableBean ์€ destroy() ๋ฉ”์„œ๋“œ๋กœ ์†Œ๋ฉธ์„ ์ง€์›ํ•œ๋‹ค.

์ถœ๋ ฅ ๊ฒฐ๊ณผ

์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = null
NetworkClient.afterPropertiesSet
connect: http://hello-spring.dev
call: http://hello-spring.dev message = ์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€
13:24:49.043 [main] DEBUG
org.springframework.context.annotation.AnnotationConfigApplicationContext -
Closing NetworkClient.destroy
close + http://hello-spring.dev

์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ๊ฐ€ ์˜์กด์„ฑ ์ฃผ์ž… ์ดํ›„์— ํ˜ธ์ถœ๋œ๋‹ค

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ข…๋ฃŒ์—๋”ฐ๋ผ ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค

๋‹จ์ 

์Šคํ”„๋ง ์ „์šฉ ์ธํ„ฐํŽ˜์ด์Šค

์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅ

โœ” ๋‚ด๊ฐ€ ์ฝ”๋“œ๋ฅผ ๊ณ ์น  ์ˆ˜ ์—†๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ ์šฉ ๋ถˆ๊ฐ€๋Šฅ

์œ„์™€ ๊ฐ™์€ ๋‹จ์ ๋“œ๋กค ์ธํ•ด ์ตœ๊ทผ์—๋Š” ์ž์ฃผ ์‚ฌ์šฉx

3. ๋นˆ ๋“ฑ๋ก, ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ ์ง€์ •

์„ค์ • ์ •๋ณด์— @Bean(initMethod = "init", destroyMethod = "close") ์ฒ˜๋Ÿผ ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ ์šฉ ์ฝ”๋“œ

// 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();
    }
}
// LifeCycleConfig.java

@Configuration
static class LifeCycleConfig {

    @Bean(initMethod = "init", destroyMethod = "close")
    public NetworkClient networkClient() {
        NetworkClient networkClient = new NetworkClient();
        networkClient.setUrl("http://hello-spring.dev");
        return networkClient;
    }
}

์„ค์ • ์ •๋ณด์— ์ดˆ๊ธฐํ™” ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์ •ํ•ด์ค€๋‹ค

์ถœ๋ ฅ ๊ฒฐ๊ณผ

์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = null
NetworkClient.init
connect: http://hello-spring.dev
call: http://hello-spring.dev message = ์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€
13:33:10.029 [main] DEBUG
org.springframework.context.annotation.AnnotationConfigApplicationContext -
Closing NetworkClient.close
close + http://hello-spring.dev

์„ค์ • ์ •๋ณด ์‚ฌ์šฉ์˜ ์žฅ์ 

๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์ž์œ ๋กญ๊ฒŒ ์ค„ ์ˆ˜ ์žˆ๋‹ค

์Šคํ”„๋ง๋นˆ์ด ์Šคํ”Œ์ด ์ฝ”๋“œ์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค

โœ” ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ์„ค์ • ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋„ ์ดˆ๊ธฐํ™”, ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์ ์šฉ ๊ฐ€๋Šฅ

์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์ถ”๋ก 

โœ” @Bean์˜ destroyMethod ๋Š” ๊ธฐ๋ณธ๊ฐ’์ด (inferred) (์ถ”๋ก )์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค.

์ถ”๋ก  ๊ธฐ๋Šฅ์€ close, shutdown์ด๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ํ˜ธ์ถœํ•ด์ค€๋‹ค

๋”ฐ๋ผ์„œ ์ง์ ‘ ์Šคํ”„๋ง๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๋ฅผ ๋”ฐ๋กœ ์ ์–ด์ฃผ์ง€ ์•Š์•„๋„ ๋™์ž‘ํ•œ๋‹ค

์ถ”๋ก  ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด destroyMethod=""์ฒ˜๋Ÿฝ ๋นˆ ๊ณต๋ฐฑ ์ง€์ •

Annotation @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() {
        connect();
        call("์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์„ธ์ง€");
    }

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

@Configuration
static class LifeCycleConfig {

    @Bean
    public NetworkClient networkClient() {
        NetworkClient networkClient = new NetworkClient();
        networkClient.setUrl("http://hello-spring.dev");
        return networkClient;
    }
}

์ถœ๋ ฅ ๊ฒฐ๊ณผ

์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = null
NetworkClient.init
connect: http://hello-spring.dev
call: http://hello-spring.dev message = ์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€
19:40:50.269 [main] DEBUG
org.springframework.context.annotation.AnnotationConfigApplicationContext -
Closing NetworkClient.close
close + http://hello-spring.dev

์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด ํŽธ๋ฆฌํ•˜๊ฒŒ ์ดˆ๊ธฐํ™”์™€ ์ข…๋ฃŒ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค

@PostConstruct, @PreDestroy์˜ ์• ๋…ธํ…Œ์ด์…˜ ํŠน์ง•

โœ” ์ตœ์‹  ์Šคํ”„๋ง์—์„œ ๊ฐ€์žฅ ๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•

๊ฐ„ํŽธํ•˜๊ณ  ํŽธ๋ฆฌ

javax ํŒจํ‚ค์ง€ ์‚ฌ์šฉ: ์Šคํ”„๋ง ์ข…์†์ ์ธ ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ผ ์ž๋ฐ” ํ‘œ์ค€ ๊ธฐ์ˆ  -> ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์—์„œ๋„ ๋™์ž‘

์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์ž˜ ์–ด์šธ๋ฆผ

๋‹จ์ : ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ ์šฉ ๋ถˆ๊ฐ€ -> @Bean ๊ธฐ๋Šฅ ์‚ฌ์šฉ

์ •๋ฆฌ

โœ” ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” @PostConstruct, @PreDestroy ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉ

โœ” ์ฝ”๋“œ๋ฅผ ๊ณ ์น  ์ˆ˜ ์—†๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ดˆ๊ธฐํ™”, ์ข…๋ฃŒํ•ด์•ผ ํ•˜๋ฉด @Bean ์˜ initMethod, destroyMethod ์‚ฌ์šฉํ•˜์ž

๋Œ“๊ธ€