@Configuration & @Bean
@Configuration과 @Bean은 Spring Framework에서 사용되는 애노테이션입니다. 이들은 Spring IoC 컨테이너에게 빈(Bean) 객체의 생성 및 구성 방법을 알려주는 역할을 합니다.
@Configuration 애노테이션은 클래스를 Spring의 설정 클래스로 지정합니다. 설정 클래스는 Spring IoC 컨테이너에게 해당 애플리케이션의 구성 정보를 제공하는 역할을 합니다. @Configuration 애노테이션이 적용된 클래스는 하나 이상의 빈을 생성하기 위해 @Bean 애노테이션과 함께 사용됩니다.
@Bean 애노테이션은 메서드를 통해 Spring IoC 컨테이너에게 빈 객체의 생성 및 구성 방법을 알려줍니다. @Bean 애노테이션이 적용된 메서드는 빈 객체를 반환하며, 이러한 빈 객체는 Spring IoC 컨테이너에 의해 관리됩니다. @Bean 애노테이션이 적용된 메서드의 이름은 빈의 이름이 되고, 반환되는 객체는 해당 빈의 인스턴스가 됩니다.
예를 들어, @Configuration과 @Bean을 사용하여 빈을 정의하는 예시입니다
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
@Bean
public AnotherBean anotherBean() {
return new AnotherBean(myBean());
}
// 다른 빈 정의 메서드...
}
위의 예시에서 AppConfig 클래스는 @Configuration 애노테이션이 적용되었으며, myBean()과 anotherBean() 메서드는 @Bean 애노테이션이 적용되어 각각 MyBean과 AnotherBean 빈을 정의합니다. anotherBean() 메서드에서는 myBean()을 참조하여 AnotherBean의 의존성 주입을 수행합니다.
이렇게 @Configuration과 @Bean을 함께 사용하여 설정 클래스에서 빈을 정의하면 Spring IoC 컨테이너가 해당 빈을 인스턴스화하고 관리합니다. 이를 통해 의존성 주입, 빈의 스코프 지정, 초기화 메서드 등을 구성할 수 있습니다.
ApplicationContext
ApplicationContext는 Spring Framework에서 IoC 컨테이너의 인터페이스입니다. IoC 컨테이너는 애플리케이션의 구성 정보를 로드하고, 빈 객체의 생성과 관리, 의존성 주입 등을 수행합니다. ApplicationContext 인터페이스는 이러한 기능을 정의하고 제공합니다.
빈(Bean) 관리: ApplicationContext는 설정된 빈 정의를 바탕으로 빈 객체의 생성과 관리를 수행합니다. 빈 객체는 @Bean 애노테이션이나 XML 설정 파일에서 정의될 수 있습니다. ApplicationContext는 빈의 스코프(싱글톤, 프로토타입 등) 및 라이프사이클 콜백(초기화, 소멸 등)을 관리합니다.
ApplicationContext 인터페이스를 사용하여 기존 자바코드로 작성하여 DI 컨테이너에 담아두었던 빈(Bean) 정의 메서드들을 ApplicationContext에 등록하여 applicationContext.getBean(”Bean의 이름”, Bean의 타입) 해당 문법을 사용하여 선택한 Bean을 호출할 수 있습니다.
→ ApplicationContext ac = new AnnotationConfigApplicationContext(설정 클래스);
ex) ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
⇒ applicationContext.getBean("memberService", MemberService.class);
public class MemberApp {
public static void main(String[] args) {
// AppConfig appConfig = new AppConfig();
// MemberService memberService = appConfig.memberService();
//AppConfig 클래스를 설정으로 사용하여, AnnotationConfigApplicationContext를 생성하고,
//애플리케이션에서 필요한 빈을 applicationContext를 통해 가져와서 사용이 가능합니다.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = " + member.getName());
System.out.println("findMember = " + findMember.getName());
}
위 코드와 같이 기존에 AppConfig 객체를 생성하여 AppConfig에 생성된 객체들을 직접 호출하는 것이 아니라 applicationContext를 이용하여 Bean을 호출하였습니다. 해당 코드를 실행하게 되면 콘솔창에 DI 컨테이너에 @Bean으로 설정된 메서드들의 객체가 등록되어 출력되는 것을 확인할 수 있습니다. 출력시에는 해당 Bean의 이름(ex.memberServie).(도트연산자)를 이용하여 출력이 가능합니다.
ApplicationContext를 스프링 컨테이너라고 합니다. 기존에는 개발자가 AppConfig를 사용해서 직접 객체를 생성하고 DI를 했지만, 이제부터는 스프링 컨테이너를 통해서 사용합니다. 스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정(구성)정보로 사용하고, 여기서 @Bean이라고 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록합니다. 이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈 (Spring Bean)이라고 합니다.
Spring Bean은 Spring Framework에서 관리되는 객체를 의미합니다. 의존성 주입(Dependency Injection, DI)은 객체 간의 의존 관계를 개발자가 직접 관리하지 않고, 외부에서 의존하는 객체를 주입하여 사용하는 디자인 패턴입니다. DI는 객체 간의 결합도를 낮추고 유연하고 재사용 가능한 코드를 작성할 수 있도록 도와줍니다. Spring Framework은 의존성 주입(Dependency Injection)을 통해 객체들을 생성, 관리, 연결하는데, 이러한 객체들을 “Spring Bean”이라고 합니다.
tmvmfld qlsdms @Bean이 붙은 메서드 명을 스프링 빈의 이름으로 사용합니다. 이전에는 개발자가 필요한 객체를 AppConfig를 사용해서 직접 조회했지만, 이제부터는 스프링 컨테이너를 통해서 필요한 스프링 빈(객체)를 찾아야 합니다. applicationContext.getBean() 메서드를 사용해서 찾을 수 있습니다.
💡 스프링 컨테이너와 빈
스프링 컨테이너를 부를 때, “BeanFactory”와 “ApplicationContext”로 구분해서 이야기합니다.
- 스프링 컨테이너의 생성과정
- new AnnotationConfigApplicationContext(AppConfig.class); 를 선언함과 동시에 스프링 컨테이너가 생성됩니다. 컨테이너가 생성되면서, 빈 이름(key), 빈 객체(value)로 만들어지는 스프링 빈 저장소가 만들어집니다. 스프링 컨테이너가 생성될 때는 구성 정보를 지정해주어야 하는데 여기선 AppConfig.class로 지정되었습니다. @Bean의 이름은 직접 부여할 수도 있습니다. ex) @Bean(name=”NewBeanName”)
- 스프링 빈 등록 AppConfig.class가 구성정보로 등록 되어있기 때문에 해당 구성 정보에서 @Bean이 붙은 메서드들을 전부 호출해줍니다 .이 때 메서드의 이름은 Bean 이름으로 해당 메서드가 반환하는 값(객체)는 Bean 객체로 등록을 해줍니다. 빈 이름은 항상 다른이름을 부여해야 합니다. 같은 이름을 부여하면, 다른 빈이 무시되거나, 기존 빈을 덮어버리는 등의 설정에 따라 오류가 발생합니다.
- 스프링 설정 파일 작성: 먼저, 스프링 컨테이너를 생성하기 위해 스프링 설정 파일을 작성합니다. 스프링 설정 파일은 일반적으로 XML, Java Config 또는 어노테이션 기반으로 작성될 수 있습니다. 설정 파일에는 애플리케이션의 구성 정보와 빈(Bean) 정의, 의존성 설정 등이 포함됩니다.
- 스프링 컨테이너 생성: 설정 파일을 기반으로 스프링 컨테이너를 생성합니다. 스프링은 다양한 종류의 컨테이너를 제공합니다. 가장 일반적인 컨테이너는 ApplicationContext 인터페이스를 구현한 클래스들입니다. ApplicationContext의 구현체는 설정 파일의 종류에 따라 다르게 선택할 수 있습니다.
- XML 기반 설정: ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, XmlWebApplicationContext 등이 사용됩니다.
- Java Config 기반 설정: AnnotationConfigApplicationContext, GenericApplicationContext 등이 사용됩니다.
- Spring Boot: Spring Boot에서는 SpringApplication 클래스의 run() 메서드를 사용하여 자동으로 스프링 컨테이너를 생성합니다.
- 빈 생성과 의존성 주입: 스프링 컨테이너는 설정 파일을 기반으로 빈 객체를 생성하고 관리합니다. 설정 파일에 정의된 빈들은 컨테이너에 의해 인스턴스화되고, 의존성 주입(Dependency Injection)을 통해 서로간의 의존성이 해결됩니다. 빈 객체는 컨테이너에 의해 스코프(싱글톤, 프로토타입 등)에 따라 관리되며, 필요한 경우 라이프사이클 콜백을 수행합니다.
- 컨테이너 사용: 스프링 컨테이너가 생성되고 빈이 초기화되면, 개발자는 컨테이너에서 필요한 빈을 가져와 사용할 수 있습니다. 컨테이너는 빈들을 관리하고, 필요에 따라 의존성 주입을 수행하여 객체 간의 결합도를 낮추고 유연한 애플리케이션을 개발할 수 있도록 도와줍니다.
- new AnnotationConfigApplicationContext(AppConfig.class); 를 선언함과 동시에 스프링 컨테이너가 생성됩니다. 컨테이너가 생성되면서, 빈 이름(key), 빈 객체(value)로 만들어지는 스프링 빈 저장소가 만들어집니다. 스프링 컨테이너가 생성될 때는 구성 정보를 지정해주어야 하는데 여기선 AppConfig.class로 지정되었습니다. @Bean의 이름은 직접 부여할 수도 있습니다. ex) @Bean(name=”NewBeanName”)
스프링 빈은 생성하고, 의존관계를 주입하는 단계가 나누어져 있습니다. 자바코드로 스프링 빈을 등록하면 생성자를 호출하면서 의존관계 주입도 한번에 처리가 됩니다.
👉 빈 이름 조회하기
class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 Bean 출력하기")
void findAllBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("bean = " + bean);
}
}
@Test
@DisplayName("애플리케이션 Bean 출력하기")
void findApplicationBean() {
String [] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
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("beanDefinitionName = " + beanDefinitionName + "object" + bean);
}
}
}
}
빈에 대한 정보 출력하기 위해서 사용 가능한 메서드들이 있습니다. 실행하면 스프링에 등록된 모든 빈 정보를 출력할 수 있습니다.
모든 빈 출력하기 getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름을 조회
getBean() : 빈 이름으로 빈 객체(인스턴스)를 조회 애플리케이션 빈 출력하기 스프링이 내부에서 사용하는 빈은 제외하고, 내가 등록한 빈만 출력 가능 / 스프링이 내부에서 사용하는 빈은 getRole()로 구분이 가능합니다.
ROLE_APPLICATION : 일반적으로 사용자가 정의한 빈 ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈
'[ BACKEND] > Spring' 카테고리의 다른 글
[SPRING] Bean 메타 정보 ( Bean Factory & Application Context) (0) | 2023.07.23 |
---|---|
[SPRING] 스프링 빈 조회 - 동일한 타입이 2개 이상 (0) | 2023.07.22 |
[SPRING] Redirect와 Fofrward (0) | 2023.07.19 |
[SPRING] 서블릿과 JSP (0) | 2023.07.18 |
[SPRING] IoC , DI , 스프링 컨테이너 (0) | 2023.07.17 |