오늘은 Spring @Bean 어노테이션과 관련해서 이야기를 하려한다. 깊게 볼 것은 아니고 특이한 거나 잘 몰랐던거? 알지만 해보지 않았던거? 그런것들을 알아볼 예정이니 그냥 이렇구나 정도만 알면 되겠다. 자주 사용될 일도 없으니 한번씩만 훑고 지나가면 될 것 같다.
요즘 회사를 이직준비 중이라 회사 다닐때 보다 더 바쁘고 스트레스 받는 것 같다.ㅠㅠ 아무튼 한번 알아보자.
Interface
버전은 언제인지 잘 모르겠는데 Interface에도 @Bean 어노테이션을 작성해도 동작한다. 아마 4.x부터 됐을 것으로 예상해보지만 그게 언제인지는 확인해보지 않았다. 예를들어 다음과 같은 설정을 해도 동작한다.
public class SomeBean {
public void print() {
System.out.println("hello world");
}
}
@Configuration
public interface BeanInterface {
@Bean
default SomeBean someBean() {
return new SomeBean();
}
}
@Configuration
public class BeanClass implements BeanInterface {
//...
}
위와 같이 작성해도
SomeBean
이라는 클래스가 Bean으로 등록된다. 여기서 주의할 것은 그에 맞기 구현체가 있어야 한다는 것이다. 만약 구현체가 없다면 Bean으로 등록되지 않는다.
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringBeanApplication.class, args);
SomeBean someBean = context.getBean(SomeBean.class);
someBean.print();
}
위와 같이 실행시키면
hello world
가 print 된 것을 알 수 있다.
@Bean 명
Bean들은 자기만의 고유한 명이 있다. 뭐 다 알겠지만 그렇다. 기본적으로 아무설정 하지 않았을 경우에는 메서드명이 빈명이 된다.
@Bean
SomeBean someBean() {
return new SomeBean();
}
위와 같이 사용할 경우 someBean이라는 이름으로 빈명이 등록이 된다.
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringBeanApplication.class, args);
String[] beanNames = context.getBeanNamesForType(SomeBean.class);
System.out.println(beanNames[0]);
}
해당 빈이름을 가져왔을 때
someBean
이라는 것이 프린트 될 것이다. 만약 빈명을 변경하고자 할 때는 @Bean 어노테이션 속성 중
value
또는
name
을 사용해서 변경 할 수 있다.
@Bean("nothing")
SomeBean someBean() {
return new SomeBean();
}
close
Spring Bean의 라이프사이클 중에
destroy
라는 자원을 해제하거나 빈이 소멸될 때 마지막으로 호출해주는 메서드들이 존재한다. 예를들어
DisposableBean
을 구현하거나
@PreDestroy
어노테이션 또는
destroyMethod
속성을 사용해서 자원 등을 해제 할 수 있다. 3가지 방법 말고도 spring 에서는 좀 더 많은 해제 법이 존재한다. 첫 번째 방법으로는
AutoCloseable
인터페이스를 구현하면 된다.
public class SomeBean implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("close");
}
}
위와 같이 작성 후에 아무 설정 없이도 SomeBean 이라는 빈이 소멸될 때 close 메서드를 실행 시킨다. 한번씩 확인해 보자.
두 번째 방법으로는 굳이
AutoCloseable
필요 없이 close 메서드만 있어도 된다.
public class SomeBean {
public void close() throws Exception {
System.out.println("close");
}
}
위와 같이 작성해도 별탈 없이 close 메서드가 실행 된다. 더 정확하게는 그냥 close 메서드를 실행 시키는 것이다. 솔직히 위의
AutoCloseable
여부와 상관없이 그냥 close 메서드를 호출하는 것이다.
마지막 방법으로는 shutdown() 메서드 이다. 이 또한 그냥 shutdown() 메서드를 호출 하는 것이다.
public class SomeBean {
public void shutdown() throws Exception {
System.out.println("close");
}
}
위와 같이 작성해도 close를 출력하는 것을 확인 할 수 있다. 만약 좀 더 확인하고 싶다면
DisposableBeanAdapter
클래스를 좀 더 확인하면 알 수 있다.
class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private static final String CLOSE_METHOD_NAME = "close";
private static final String SHUTDOWN_METHOD_NAME = "shutdown";
//...
}
참고로 DisposableBean 인터페이스와 위의 세가지 방법을 같이 쓰면 DisposableBean 의 destroy
메서드가 우선순위가 높다.
Lite Mode
Spring Bean에는 lite 모드라는 것이 있다. 그게 뭐냐고 물어보면 조금 뭐라고 해야할지.. lite니까 조금 가벼운거?
아무튼 lite 모드는 해당 설정에
@Configuration
어노테이션이 아닌
@Component
어노테이션을 작성하면 그게 lite mode가 된다. lite 모드로 하면 설정이 Configuration으로 하는 것보다는 빠르지만 그렇게 확 티가 날 정도는 아닌 걸로 기억하고 있다. 물론 많으면 말이 달라지겠지만.. 아무튼 그럼 차이가 뭘까? 차이는 Cglib을 사용하냐 하지 않느냐 차이가 가장 큰 차이 같다.
@Configuration 같은 경우에는 cglib을 사용하지만
@Component
경우에는 cglib을 사용하지 않는다.
@Configuration
public class Config {
@Bean
SomeBean someBean() {
return new SomeBean();
}
@Bean
NothingBean nothingBean() {
return new NothingBean(someBean());
}
}
예를 들어 위와 같은 설정이 있다고 가정하자. NothingBean은 SomeBean을 디펜더시 받고 있다. 그래서 위와 같이 설정을 했다고 하자. 그럼 someBean 의 메서드는 몇 번 호출 이 될까? 일반적으로 볼 때에는 두번 호출 되는 게 맞다고 생각한다. SomeBean을 빈으로 등록할 때와 NothingBean을 빈으로 등록할 때 someBean() 메서드를 호출하니 두번이 맞다. 하지만
@Configuration
를 사용하면 아까 말했다시피 cglib을 이용해서 위의 someBean을 한번만 호출 하도록 한다.
@Component
public class Config {
@Bean
SomeBean someBean() {
return new SomeBean();
}
@Bean
NothingBean nothingBean() {
return new NothingBean(someBean());
}
}
하지만 이 경우에는 어떨까? 이 경우에는 우리가 일반적으로 생각하는게 맞다. 이 때에는 someBean() 메서드가
두번
호출된다.
@Configuration 은 cglib을 사용해서 일반적으로 @Component 를 사용할 때보다 조금 느린것 같다. 하지만 그 차이는 눈에 보이지 않는 다는 거..
만약 config을 lite mode로 사용할 경우에는 좀 더 신중하게 사용해야 될 듯 싶다. 그냥 필자는
@Configuration
을 사용하련다..
오늘은 Spring의 Bean에 대해서 몇 가지 알아봤다. Spring을 사용하는데에는 아주 쓸모있는 기능은 아니지만 알아둬서 나쁠껀 없으니 한번씩 해보도록 하자.