//1. 컨테이너 초기화
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppContext.class);
//2. 컨테이너에서 빈 객체를 구해서 사용
Greeter g = ctx.getBean("greeter", Greeter.class);
String msg = g.greet("스프링");
System.out.println(msg);
//3. 컨테이너 종료
ctx.close();
객체 생성 -> 의존 설정 -> 초기화 -> 소멸
빈객체를 초기화 하고 소멸하기 위해 빈 객체의 지정한 메서드를 호출한다.
org.springframework.beans.factory.InitializingBean
public interface InitializingBean { void afterPropertiesSet() throws Exception; }
- 빈 객체가 InitializingBean 인터페이스를 구현한다.
- 스프링 컨테이너는 초기화 과정에서 빈 객체의 afterPropertiesSet() 메서드를 실행한다.
- 빈 객체를 생성한 뒤에 초기화 과정이 필요하면 InitializingBean 인터페이스를 상속하고 afterPropertiesSet()메서드를 알맞게 구현하면 된다.
org.springframework.beans.factory.DisposableBean
public interface DisposableBean { void destroy() throws Exception; }
- 스프링 컨테이너는 빈 객체가 DisposableBean 인터페이스를 구현한 경우 소멸 과정에서 빈 객체의 destroy() 메서드를 실행한다.
- 빈 객체의 소멸 과정이 필요하면 DisposableBean 인터페이스를 상속하고 destroy()메서드를 알맞게 구현하면 된다.
데이터베이스 커넥션풀
- 커넥션 풀을 위한 빈 객체는 초기화 과정에서 데이터베이스를 연결을 생성한다.
- 컨테이너를 사용하는 동안 연결을 유지하고,
- 빈 객체를 소멸할 때 사용중인 데이터베이스 연결을 끊어야 한다.
채팅 클라이언트
- 채팅클라이언트와 서버의 연결을 시작하면 빈 객체를 초기화 하고,
- 채팅을 종료할 때 빈 객체를 소멸하여 채팅클라이언트와 서버의 연결을 종료한다.
package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.Client;
@Configuration
public class AppCtx {
@Bean
public Client client() {
Client client = new Client();
client.setHost("host");
return client;
}
}
package spring;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Client implements InitializingBean, DisposableBean {
private String host;
public void setHost(String host) {
this.host = host;
}
//채팅 클라이언트 빈 객체 초기화로 서버와 연결 시작
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Client.afterPropertiesSet() 실행");
}
public void send() {
System.out.println("Client.send() to " + host);
}
//채팅 클라이언트 빈 객체 소멸로 서버와 연결 종료
@Override
public void destroy() throws Exception {
System.out.println("Client.destroy() 실행");
}
}
package main;
import java.io.IOException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import config.AppCtx;
import spring.Client;
public class Main {
public static void main(String[] args) throws IOException {
AbstractApplicationContext ctx =
new AnnotationConfigApplicationContext(AppCtx.class);
Client client = ctx.getBean(Client.class);
//출력 : Client.afterPropertiesSet() 실행
client.send();
//출력 : Client.send() to host
ctx.close();
//출력 : Client.destroy() 실행
}
}
직접 구현한 클래스가 아닌 외부에서 제공받은 클래스를 스프링 빈 객체로 설정하고 싶을때
스프링 설정에서 직접 메서드를 지정하는 방법
package spring;
public class Client2 {
private String host;
public void setHost(String host) {
this.host = host;
}
public void connect() {
System.out.println("Client2.connect() 실행");
}
public void send() {
System.out.println("Client2.send() to " + host);
}
public void close() {
System.out.println("Client2.close() 실행");
}
}
@Bean(initMethod = "connect", destroyMethod = "close")
@Scope("singleton")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
return client;
}
package main;
import java.io.IOException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import config.AppCtxWithPrototype;
import spring.Client;
public class MainWithPrototype {
public static void main(String[] args) throws IOException {
AbstractApplicationContext ctx =
new AnnotationConfigApplicationContext(AppCtxWithPrototype.class);
Client client2 = ctx.getBean(Client.class);
//출력 : Client2.connect() 실행
client2.send();
//출력 : Client2.send() to host
ctx.close();
////출력 : Client2.destroy() 실행
}
}
초기화 코드는 설정클래스에서 자바코드이기 때문에 직접 메서드를 호출할 수 있다.
@Bean(destroyMethod = "close")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
client.connect();
return client;
}
connect()메서드를 이용해서 초기화를 해줄 수 도 있다.
초기화 관련 메서드를 빈 설정 코드에서 직접 실행 할때 주의점
@Bean
public Client client() {
Client client = new Client();
client.setHost("host");
client.afterPropertiesSet();
return client;
}
스프링 컨테이너는 빈 객체를 한 개만 생성한다.
Client client1 = ctx.getBean("client", Client.class);
Client client2 = ctx.getBean("client", Client.class);
//client1 == client2 -> true
위와 같이 한 식별자에 대해 한 개의 객체만 존재하는 빈은 싱글톤 범위를 갖는다.
@Bean
@Scope("prototype")
public Client client() {
Client client = new Client();
client.setHost("host");
return client;
}
@Bean
@Scope("singleton")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
return client;
}
주의!
- 프로토타입 범위를 갖는 빈은 완전한 빈의 라이프사이클을 따르지 않는다.
- 즉, 스프링 컨테이너는 프로토타입의 빈 객체를 생성하고 프로퍼티를 설정하고 초기화 작업까지는 수행하지만
- 컨테이너를 종료한다고 해서 생성한 프로퍼티타입 빈 객체의 소멸 메서드를 실행하지 않는다.
- 따라서, 프로토타입 범위의 빈을 사용할 때에는 빈 객체의 소멸 처리를 코드에서 직접 해야 한다.