스프링 컨테이너와 스프링 빈(Bean)
스프링 컨테이너란, 스프링 빈(Bean)을 저장하고 관리하는 저장소입니다.
스프링 빈(Bean)은 스프링 컨테이너에 의해 관리되는 재사용 가능한 소프트웨어 컴포넌트입니다.
즉, 스프링 컨테이너가 관리하는 자바 객체를 뜻하며, 하나 이상의 빈(Bean)을 관리한다. 빈은 인스턴스화된 객체를 의미하며, 스프링 컨테이너에 등록된 객체를 스프링 빈이라고 합니다.
스프링 컨테이너를 생성할 때는 구성 정보를 지정해주어야 합니다. 이 구성 정보는 XML을 기반으로 만들 수 있고, 자바 에너테이션 기반의 자바 설정 클래스로도 만들 수 있습니다. (이 외에도 Groovy, json 등 다양한 형식의 파일도 가능합니다.) 이번 포스팅은 이 2가지 방법을 사용하여 스프링 컨테이너와 빈을 생성하는 방법에 대해서 작성하였습니다.
스프링 컨테이너 생성
스프링 컨테이너는 ApplicationContext를 이용하여 만들 수 있습니다.
ApplicationContext
ApplicationContext는 인터페이스입니다.
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
자바 설정 클래스
우선, 애너테이션을 기반으로 한 자바 설정 클래스를 구성 정보로 하여 스프링 컨테이너를 생성해 보겠습니다. 예전에는 XML을 이용한 설정 파일을 대부분이었지만, 최근 와서는 자바 클래스를 설정 파일로 하는 경우가 대부분입니다. 자바 설정 클래스를 이용하기 위해서는 ApplicationContext를 구현하는 구현체 중 AnnotationConfigApplicationContext를 사용해야 합니다.
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
위와 같이 작성하면 AppConfig.class 파일 안에 정의된 빈(Bean)들을 ApplicationContext (스프링 컨테이너)에 등록함으로써 스프링 컨테이너가 관리할 수 있도록 합니다. 따라서, AppConfig.class에 빈(Bean)을 정의해주어야 합니다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(
memberRepository(),
discountPolicy());
}
@Bean
private static DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
@Bean
private static MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
이렇게 에너테이션을에너테이션을 이용하여 빈을 정의할 수 있습니다. 빈을 정의하는 방법은 다양하게 있는데, 우선 이번 포스팅은 이렇게 @Configuration과 @Bean 에너테이션을 이용하여 빈을 정의하였습니다. (빈 정의 방법에 대해서는 다음 포스팅에서 작성해 보겠습니다.)
즉, 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 이용해 스프링 빈을 스캔하여 등록하게 되는 것입니다.
XML 설정 파일
최근에는 Spring Boot를 많이 사용하면서 XML 기반의 설정은 잘 사용하지 않습니다. 하지만, 아직 레거시 프로젝트들이 대부분 XML로 되어 있고, XML을 이용하면 컴파일 없이 빈 설정 정보를 변경할 수 있는 장점도 있어 알아두는 것이 좋을 것 같습니다.
XML 설정 파일을 사용하려면 ApplicationContext의 구현체 중 나인 GenericXmlApplicationContext를 사용하면서 XML 설정 파일을 넘기면 됩니다.
ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
클래스 설정 파일과 동일하게 appConfig.xml 파일 안에 정의된 빈(Bean)들을 ApplicationContext (스프링 컨테이너)에 등록함으로써 스프링 컨테이너가 관리할 수 있도록 합니다. 따라서, appConfig.xml에 빈(Bean)을 정의해주어야 합니다. 해당 xml 파일은 src/main/resources 경로에 존재합니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="memberService" class="hello.core.member.MemberServiceImpl">
<!--MemberServiceImpl 객체를 생성자-->
<constructor-arg name="memberRepository" ref="memberRepository" /> <!--아래 id = "memberRepository"를 참조하도록 ref 속성 설정-->
</bean>
<bean id="memberRepository"
class="hello.core.member.MemoryMemberRepository" />
<bean id="orderService" class="hello.core.order.OrderServiceImpl">
<!--OrderServiceImpl 객체 생성자-->
<constructor-arg name="memberRepository" ref="memberRepository" />
<constructor-arg name="discountPolicy" ref="discountPolicy" />
</bean>
<bean id="discountPolicy" class="hello.core.discount.RateDiscountPolicy" />
</beans>
전체 패키지 구조
스프링 빈 조회하기
위에서 컨테이너에 등록된 빈을 모두 조회해보도록 하겠습니다. (자바 설정 클래스나 XML 설정 파일 둘 다 같은 빈을 정의하고 있기 때문에 어떤 설정 정보를 사용해도 무관합니다.)
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
// ac에 등록된 모든 빈들의 이름을 가져온다.
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName); // 빈 이름으로 빈 객체를 조회한다.
System.out.println("name = " + beanDefinitionName + ", " + " object = " + bean);
}
}
}
[결과]
출력 결과, 아래와 같이 스프링 컨테이너에 등록된 빈들의 정보를 확인할 수 있습니다.
하지만, 위 정보들은 개발자가 직접 등록한 빈 외에 스프링 내부에서 사용하는 다른 빈들의 정보도 모두 출력하여 줍니다. 따라서 개발자가 직접 등록한 빈의 정보만 출력하고 싶다면 아래와 같이 코드를 변경하여야 합니다.
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
/*String[] beanDefinitionNames = ac.getBeanDefinitionNames(); // ac에 등록된 모든 빈들의 이름을 가져온다.
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName); // 빈 이름으로 빈 객체를 조회한다.
System.out.println("name = " + beanDefinitionName + ", " + " object = " + bean);
}*/
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
// getBeanDefinition을 사용하려면 ApplicationContext가 아닌
// AnnotationConfigApplicationContext를 사용해야 한다.
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
//Role ROLE_APPLICATION: 개발자가 직접 등록한 애플리케이션 빈
//Role ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + ", " + " object = " + bean);
}
}
}
}
주의할 점은, 스프링 컨테이너는 ApplicationContext 타입이 아니라 AnnotationConfigApplicationContext이어야 BeanDefinition 정보를 가져올 수 있습니다.
[결과]
이렇게 스프링 컨테이너가 무엇이고 스프링 빈은 어떻게 등록하고 조회할 수 있는지 살펴보았습니다. 다음 포스팅에서는 이번 포스팅에 이어 스프링 빈을 조회하는 다양한 방법과 BeanDefinition에 대해서 자세히 다루었으니 확인해보시면 좋을 것 같습니다!
[전체 소스코드]
GitHub - eunhwa99/Spring
Contribute to eunhwa99/Spring development by creating an account on GitHub.
github.com
[참고자료]
https://ittrue.tistory.com/221#google_vignette
[Spring] 스프링 빈(Bean)이란 무엇인가?
빈(Bean) 빈(Bean)은 스프링 컨테이너에 의해 관리되는 재사용 가능한 소프트웨어 컴포넌트이다. 즉, 스프링 컨테이너가 관리하는 자바 객체를 뜻하며, 하나 이상의 빈(Bean)을 관리한다. 빈은 인스
ittrue.tistory.com
김영한, "스프링 핵심 원리 - 기본편", 인프런