Spring Container?
ApplicationContext는 Interfaced이다.
Spring Container는 XMl 기반으로 생성 또는 Annotation기반 자바설정 클래스로 생성.
∙ Spring Container는 @Configuration
Annotation을 가진 클래스를 구성정보로 사용한다.
∙ @Bean
이라고 적힌 Method를 모두 호출해서 반환된 객체를 Spring Container에 등록한다.(Spring Bean)
∙ applicationContext.getBean("메서드명",클래스명.class)
를 통해 SpringBean 을 찾을 수 있다.
(implement) applicationContext.getBean(클래스명.class)
또는 구현체.class
를 통해서도 SpringBean 을 찾을 수 있다.
∙ Spring Bean 조회 시 상속관계가 존재 할 경우에는 부모타입으로 조회시 자식타입도 모두 조회된다.
BeanFactory & ApplicationContext
∙ Application Context는 Bean의 모든 기능 + 부가기능을 제공한다.
Application Context 의 부가기능 |
부가기능 설명 |
---|---|
MessageSource |
국제화기능(언어) |
EnvironmentCapable |
Local,dev,prod 구분하여 처리 |
ApplicationEventPublisher |
이벤트 발행, 구독하는 모델 편리하게지원 |
ResourceLoader |
파일,클래스패스,외부 등에서 리소스 편리하게 조회 |
+-------------+
|Bean Factory |
|(interface) |
+-------------+
↑ (implement)
+-------------+
|App Context |
|(interface) |
+-------------+
↑ (implement)
+------------------+
|AnnotationConfig |
|ApplicationContext| --> AppConfig.class
+------------------+
Bean의 구현체가 여러개일 때
2. @Qualifier("beanName") -> beanName으로 지정된 빈 주입
3. Set 또는 List로 받기
4. Property 이름을 bean 과 동일하게하기. 가장 흔히 사용
Bean 의 Scope
∙ Prototype 매번 새로만드는 방법 (데이터 클리어 필요 시)
Session: 세션마다 계속 새로 만듦
WebSocket: 양방향 실시간 통신
Spring의 환경설정
∙ 클래스단위에 적용하거나 메서드 단위에 적용가능
BeanDefinition
∙ BeanDefiniation(Bean 설정 Meta Info)
은 “역할과 구현을 개념적으로 나눈 것” 즉, 추상화 이다.
∙ AnnotationConfigApplicationContext
는 AnnotatedBeanDefinitionReader
를 사용해서 App.Config.class
를 읽고 BeanDefinition
을 생성한다.
BeanDefinition | |
---|---|
BeanClassName | 생성할 빈의 클래스명(자바설정처럼 팩토리 역할의 빈을 사용하면 없음.) |
factoryBeanName | 팩토리 역할의 빈을 사용할 경우 이름 |
factoryMethodName | 빈을 생성할 팩토리 메서드 지정 |
Scope | 싱글톤(Default) |
LazyInit | 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라 실제 빈을 사용할 때 까지 최대한 생성을 지연처리하는 지 여부 |
InitMethodName | 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드명 |
DestroyMethodName | 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드명 |
Constructor arguments Properties |
의존관계 주입에서 사용. (자바설정처럼 팩토리 역할의 빈을 사용하면 없음) |
Bean 생명주기 Callback
[Spring Bean 은 간단히 다음과 같은 LifeCycle을 가진다]
” Object생성 - > DI “
또한 Spring Container가 종료되지 직전에 소멸 Callback을 준다.
따라서 안전하게 종료 작업을 진행 할 수 있다.
[Spring Bean 의 event LifeCycle]-(Singleton) Spring Container 생성 -> Spring Bean 생성 -> 의존관계 주입 ->초기화 콜백 -> 사용 -> 소멸전 콜백 -> Spring 종료
++참고 : 객체의 생성과 초기화는 분리하도록 하자
생성자는 필수정보(파라미터)를 받고, 메모리를 할당해 객체를 생성하는 책임을 가진다. 반면 초기화는 이렇게 생성된 값들을 활용해 외부커넥션을 연결하는 등 무거운 동작을 수행한다.
따라서 생성자 안에서 무거운 초기화 작업을 진행하기보다는 객체생성부분과 초기화 부분을 명확하게 나누는 것이 유지보수관점에서 좋다. 물론 초기화 작업이 내부 값들만 약간 변경하는 정도로 단순한 경우에는 생성자에서 한번에 다 처리하는게 나을 때도 있다!
Bean LifeCycle Callback (InterFace)
Interface(InitializingBean, DisposableBean)
//InitializingBean , DisposableBran Interface
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);
}
//afterPropertiesSet Method(by InitializingBean i/f)
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("NetworkClient.afterPropertiesSet");;
connect();
call("초기화 연결메세지");
}
//destroy Method (by DisposableBean)
@Override
public void destroy() throws Exception {
System.out.println("NetworkClient.destroy");
disconnect();
}
}
출력결과
생성자 호출, urlnull
NetworkClient.afterPropertiesSet
connect :http://hello.com
call : http://hello.com message :초기화 연결메세지
15:13:11.816 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@22a637e7, started on Sat May 13 15:13:11 KST 2023
NetworkClient.destroy
close http://hello.com
초기화,소멸 Interface의 단점
초기화,소명 메서드의 이름을 변경할 수 없다
내가 코드를 고칠수 없는 외부라이브러리에 적용할 수 없다.
Bean LifeCycle Callback (Method)
임의 메서드 방식의 장점
Spring Bean이 Spring Code에 의존하지 않는다.
코드가 아니라 설정정보를 사용하므로, 코드를 고칠 수 없는 외부라이브러리에도 초기화,종료메세지를 사용할 수 있다.
사용예시(1)
public void init() {
System.out.println("NetworkClient.init");
connect();
call("초기화 연결메세지");
}
public void close() {
System.out.println("NetworkClient.close");
disconnect();
}
public class BeanLifeCycleTrst {
@Test
public void lifeCycleTest() {
AnnotationConfigApplicationContext 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://hello.com");
return networkClient;
}
}
}
출력결과(1)
생성자 호출, urlnull
NetworkClient.init
connect :http://hello.com
call : http://hello.com message :초기화 연결메세지
15:33:48.088 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@22a637e7, started on Sat May 13 15:33:47 KST 2023
NetworkClient.close
close http://hello.com
설정정보 사용 특징
외부 라이브러리들은 대부분 `close` ,`shutdown`이라는 종료메서드 를 사용.
`@Bean` 의 `destroyMethod`는 기본값이 `(inferred)`이다.
이 기능은 `close`, `shutdown` 의 이름을 가진 메서드를 자동으로 호출해준다. 즉, inferred 뜻 그대로 추론하여 종료메서드들을 호출해준다. 따라서 Spring Bean으로 등록하면 굳이 다른 종료메서드를 적어줄 필요가 없다.
사용을 원하지 않을 시에는 `destroyMethod=""`이렇게 공백을 넣어두면 된다.
Bean LifeCycle Callback (Annotation)
최신 Spring에서 권장하는 방식이다.
메서드에 @PostConstruct
, @PreDestory
를 붙여주기만 하면 된다!
Component 과도 호환이 편하다.
유일한 단점은 외부라이브러리에 적용하기 힘들다는 것이다. 외부라이브러리 초기화,종료 필요시 위의 메서드방식을 사용하면 된다. @Bean(initMethod = "init",destroyMethod = "close")
@PostConstruct
public void init() {
System.out.println("NetworkClient.init");
connect();
call("초기화 연결메세지");
}
@PreDestroy
public void close() {
System.out.println("NetworkClient.close");
disconnect();
}