일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- BEAN
- cache
- 프로토타입
- DB
- javascript
- VUE
- vuex
- HTTP
- dependency injection
- Singleton
- Java
- Vue.js
- 의존성 주입
- 싱글톤
- thymeleaf
- Stateless
- Excel
- js
- 캐시
- Security
- 로그인
- vue-cli
- HTTP 메서드
- Setter
- Kotlin
- di
- 라이프 사이클
- JPA
- Repository
- Spring
- Today
- Total
jhhan의 블로그
스프링 코어(14-1) - 빈 생명주기 콜백 - 3가지 방식 본문
이전 포스트에서 말한대로 빈 생명주기 콜백을 지원하는 3가지 방식에 대해 알아보겠습니다.
스프링은 크게 3가지 방식으로 빈 생명주기 콜백을 지원합니다.
- 인터페이스(InitializingBean, DisposableBean)
- 설정 정보에 직접 추가
- 애노테이션(@PostConstruct, @PreDestroy)
1. 인터페이스(InitializingBean, DisposableBean)
인터페이스를 이용하는 방식입니다.
먼저 NetworkClient 클래스입니다.
public class NetworkClient implements InitializingBean, DisposableBean {
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("disconnect : " + url);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("NetworkClient.afterPropertiesSet");
connect();
call("초기화 연결 메세지");
}
@Override
public void destroy() throws Exception {
System.out.println("NetworkClient.destroy");
disconnect();
}
}
InitializingBean과 DisposableBean 인터페이스를 이용하는 방식입니다.
- InitializingBean은 afterPropertiesSet() 을 오버라이딩
- DisposableBean은 destroy() 을 오버라이딩 해서 진행합니다.
그리고 BeanLifeCycleTest 클래스를 실행해 봅니다.
- 생성자 호출을 할 때는 역시 url이 null입니다.
- 하지만 connect() 를 호출할 때부터는 다릅니다.
- setUrl()로 설정한 url값이 나오기 시작합니다.
- afterPropertiesSet() 을 통해 초기화를 지원해준다는 것을 알 수 있습니다.
- destroy() 를 통해 소멸 직전에 작동한다는 것을 알 수 있습니다.
이렇게 인터페이스를 이용해서 진행할 수 있습니다.
하지만 인터페이스를 이용하는 방식은 몇 가지 단점이 있습니다.
- 인터페이스가 스프링 전용 → 스프링에 전적으로 의존하게 됨
- afterPropertiesSet(), destroy() 라는 이름으로 고정 → 메서드 이름을 바꾸고 싶어도 바꿀 수 없음
- 외부 라이브러리에 적용X
이렇게 있습니다.
참고로 인터페이스를 이용하는 방식은 스프링 초창기에 나온 방법입니다.
따라서, 요즘은 잘 사용하지 않는 방식입니다.
이런 것이 있다라고 알아두면 좋을 것 같습니다.
2. 설정 정보에 직접 추가
설정 정보에 초기화 메서드, 소멸 메서드를 직접 추가하는 방식입니다.
바로 코드로 살펴보겠습니다.
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("disconnect : " + url);
}
public void init() throws Exception {
System.out.println("NetworkClient.init");
connect();
call("초기화 연결 메세지");
}
public void close() throws Exception {
System.out.println("NetworkClient.close");
disconnect();
}
}
1번에서 추가한 인터페이스는 제거합니다.
그리고 init(), close()라는 이름으로 변경해서 진행합니다.
다음은 BeanLifeCycleTest 클래스입니다.
public class BeanLifeCycleTest {
@Test
public void lifeCycleTest() {
// ApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class); : ApplicationContext는 close() 메소드를 제공하지 않음
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
NetworkClient client = 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://spring-core.cycle");
return networkClient;
}
}
}
@Bean 애노테이션 옆에 옵션을 주면 됩니다.
- initMethod: 아까 init으로 설정했으니 그 이름을 넣습니다.
- destoryMethod: 아까 close로 설정했으니 그 이름을 넣습니다.
- 사실 옵션 이름만 봐도 대충 눈치챌 수 있습니다.
이제 실행해봅니다.
역시 동일하게 잘 동작합니다.
설정 정보를 직접 추가하면서 다음과 같은 이점이 있습니다.
- 메서드 이름을 자유롭게 설정 가능
- 스프링 코드에 의존X
- 설정 정보를 이용하기 때문에 외부 라이브러리에도 적용가능
- 모두 인터페이스에서의 단점을 개선한 것으로 볼 수 있습니다.
그리고 추가된 기능이 있습니다.
destroyMethod 옵션이 없어도 동작한다는 것입니다.
실제로 destroyMethod 옵션만 지우고 실행해봐도 결과는 똑같이 나오는 것을 알 수 있습니다.
어떻게 이럴 수 있을까요?
- 대부분의 종료 메서드는 close, shutdown 같은 이름을 사용합니다.
- 그래서 옵션에 추가하지 않아도
- close나 shutdown의 이름을 가진 메서드를 자동으로 호출합니다.
- 그래서 종료 메서드가 동작하는 것입니다.
- 만약 destroyMethod 옵션이 동작하기를 원하지 않는다면 destoryMethod=""로 하면 동작하지 않습니다.
실제로 동작하지 않는군요.
이 방법에도 단점이 있습니다.
바로 개발자가 직접 입력하기 때문에 개발자가 실수하면 에러가 발생한다는 점입니다.
그래서 보통은 3번째를 많이 사용한다고 합니다.
3. 애노테이션(@PostConstruct, @PreDestroy)
애노테이션을 이용하는 방법입니다.
바로 코드로 알아보죠.
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("disconnect : " + url);
}
@PostConstruct
public void init() throws Exception {
System.out.println("NetworkClient.init");
connect();
call("초기화 연결 메세지");
}
@PreDestroy
public void close() throws Exception {
System.out.println("NetworkClient.close");
disconnect();
}
}
public class BeanLifeCycleTest {
@Test
public void lifeCycleTest() {
// ApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class); : ApplicationContext는 close() 메소드를 제공하지 않음
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://spring-core.cycle");
return networkClient;
}
}
}
- 애노테이션을 추가하면 됩니다.
- @PostConstruct : 대충 생성자 이후 라는 의미입니다. 생성자 이후에 동작하는 것을 추론할 수 있습니다.
- @PreDestroy : 대충 소멸 전 이라는 의미입니다. 소멸 전에 동작하는 것을 추론할 수 있습니다.
- 그리고 @Bean에는 옵션을 주지 않습니다.
그리고 실행한다면 역시 같은 결과가 나온다는 것을 알 수 있습니다.
아까 설정정보를 추가하는 것보다 훨씬 간편하네요!
장점.
- 애노테이션만 붙이면 되기 때문에 굉장히 편리합니다.
- 애노테이션의 패키지를 보면 javax로 시작합니다. → 스프링에 의존하지 않습니다.
- 그래서 스프링이 아닌 다른 곳에서도 잘 동작합니다.
- 컴포넌트 스캔과 같이 사용해도 문제가 없습니다.
- 스프링에서도 애노테이션 사용을 권장합니다.
단점.
- 외부 라이브러리에는 적용불가 → 유일한 단점입니다.
- 혹시 외부 라이브러리에 적용을 해야한다면 2번에서 배운 설정 정보를 직접 추가해야 합니다.
정리.
- 애노테이션(@PostConstruct, @PreDestroy)을 사용하자.
- 외부 라이브러리의 경우 @Bean의 initMethod, destroyMethod를 사용하자.
입니다.
이렇게 3가지 지원방식에 대해서 알아봤습니다.
포스트를 마치겠습니다.
출처: 인프런 - 스프링 핵심원리(기본편) by 김영한
'Spring' 카테고리의 다른 글
스프링 코어(16) - 프로토타입과 싱글톤을 같이 쓰는 경우 (0) | 2021.10.04 |
---|---|
스프링 코어(15) - 빈 스코프 : 프로토타입 (0) | 2021.09.22 |
스프링 코어(14) - 빈 생명주기 콜백 (0) | 2021.08.16 |
스프링 코어(번외-2) - 스프링 빈의 자동 & 수동 등록 (0) | 2021.08.15 |
스프링 코어(13) - 조회 빈이 모두 필요한 경우 (0) | 2021.08.15 |