import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
/* 1. 컨테이너 초기화: Bean 객체의 생성, 의존 주입, 초기화 작업 수행 */
AnnotationConfigApplicationContext ctx
= new AnnotationConfigApplicationContext(AppContext.class);
/* 2. 컨테이너에서 getBean() 등의 메서드로 Bean 객체를 가져와서 사용 */
Greeter g = ctx.getBean("greeter", Greeter.class);
String msg = g.greet("스프링");
System.out.println(msg);
/* 3. 컨테이너 종료: Bean 객체의 소멸 */
ctx.close();
}
}
Spring 컨테이너의 초기화를 수행할 때, 컨테이너는 우선 Bean 객체를 생성하고 의존 자동 주입을 통해 의존을 설정한다. 그리고 모든 의존 설정이 완료되면 Bean 객체의 초기화를 수행하기 위해 Bean 객체의 지정된 메서드를 호출한다. Spring 컨테이너를 종료할 때, 컨테이너는 Bean 객체의 소멸을 처리하기 위한 close() 메서드를 호출한다.
Spring은 다음의 두 인터페이스에서 Bean 객체 초기화 및 소멸 메서드를 정의한다.
만약 DB 커넥션 풀이나 채팅 클라이언트처럼 Bean 객체의 초기와와 소멸 과정을 별도로 구현해야 하는 경우, 아래의 인터페이스를 상속받아 지정된 메서드를 알맞게 구현하는 방식으로 사용한다.
org.springframework.beans.factory.InitializingBean인터페이스
Bean 객체 초기화를 수행하는afterPropertySet()메서드를 정의한다.org.springframework.beans.factory.DisposableBean인터페이스
Bean 객체 소멸을 위한destroy()메서드 정의
package spring;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/* Client: Bean 객체로 생성할 클래스*/
public class Client implements InitializingBean, DisposableBean {
private String host;
public void setHost(String host) {
this.host = host;
}
/* InitializingBean 인터페이스의 afterPropertiesSet() 메서드 구현 */
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Client.afterPropertiesSet() 실행");
}
public void send() {
System.out.println("Client.send() to " + host);
}
/* DisposableBean 인터페이스의 destroy() 메서드 구현 */
@Override
public void destroy() throws Exception {
System.out.println("Client.destroy() 실행");
}
}
InitializingBean 인터페이스와 DisposableBean 인터페이스를 상속받아 구현할 수 없거나 외부에서 제공받은 클래스를 Spring Bean 객체로 설정하고자 하는 상황이라면 사용자가 직접 Bean 초기화 메서드와 소멸 메서드를 구현해야 한다.
@Bean(initMethod = "메서드명", destroyMethod = "메서드명")
사용자가 직접 Bean 객체 초기화 및 소멸 메서드를 구현했을 경우,@Bean어노테이션에서initMethod속성과destroyMethod속성에 초기화 메서드와 소멸 메서드를 각각 지정하면 Spring에서는 해당 메서드를 통해 Bean 객체의 초기화와 소멸 처리를 수행한다.
package spring;
public class Client2 {
private String host;
public void setHost(String host) {
this.host = host;
}
/* connect(): Bean 객체 초기화 시 실행할 사용자 정의 메서드 */
public void connect() throws Exception {
System.out.println("Client2.connect() 실행");
}
public void send() {
System.out.println("Client2.send() to " + host);
}
/* close(): Bean 객체 소멸 시 실행할 사용자 정의 메서드 */
public void close() throws Exception {
System.out.println("Client2.close() 실행");
}
}
package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.Client2;
@Configuration
public class AppCtx {
/* 사용자가 정의한 connect(), close() 메서드를 Bean 초기화, 소멸 메서드로 지정 */
@Bean(initMethod = "connect", destroyMethod = "close")
public Client2 client2() {
Client2 client2 = new Client2();
client2.setHost("host");
return client2;
}
}
Spring 컨테이너는 별도의 설정이 없다면 기본적으로 1개의 Bean 식별자에 대해 1개의 Bean 객체를 생성한다. 이렇게 생성된 Bean은 싱글톤 범위를 가지므로, 참조변수가 서로 다르더라도 결국 동일한 Bean 객체를 참조하게 된다. 또한 Spring 컨테이너는 싱글톤 범위를 갖는 Bean 객체의 생명주기 전체를 관리한다.
Spring 컨테이너에서 @Scope를 이용하여 Bean의 범위를 프로토타입으로 지정한 경우, Bean 객체를 구할 때마다 매번 새로운 객체를 생성하므로 1개의 Bean 식별자에 대해 여러 개의 Bean 객체를 생성할 수 있다. 따라서 Bean 객체의 참조변수가 서로 다르다면 각각의 참조변수는 서로 다른 객체를 참조하게 된다.
그리고 Bean 객체가 프로토타입 범위를 가질 경우 Spring 컨테이너는 Bean 객체의 생명주기 중 Bean 객체의 생성과 초기화 단계까지만 관리할 뿐, Bean 객체의 소멸까지는 다루지 않는다.
따라서 프로토타입 Bean 객체를 사용한다면 사용자가 직접 Bean 객체 소멸 처리 코드를 작성하여 수동으로 Bean 객체의 소멸 처리를 수행해야 한다.
@Scope
@Bean어노테이션과 함께 사용되며, 특정 Bean의 관리 범위를 명시적으로 설정할 때 사용하는 어노테이션이다.@Scope("singleton")
: 지정된 Bean의 관리 범위를 싱글톤 범위로 설정한다.@Scope("prototype")
: 지정된 Bean의 관리 범위를 프로토타입 범위로 설정한다.