Instantiation Beans
Bean Definition은 본질적으로 하나 이상의 객체를 생성하기 위한 레시피입니다. 컨테이너는 빈 객체 생성 요청 시에 명명된 빈의 레시피를 확인하고, 해당 빈 정의에 캡슐화된 구성 메타데이터(BeanDefinition의 속성에 저장됨)를 사용하여 실제 객체를 생성(또는 획득)합니다.
해당 빈 정의에 캡슐화된 구성 메타데이터란?
"해당 빈 정의에 캡슐화된 구성 메타데이터"는 빈을 생성하는 데 필요한 모든 정보를 담고 있으며, 이 정보는 스프링에서 BeanDefinition 객체의 속성들에 저장됩니다.
BeanDefinition 객체의 주요 속성들
BeanDefinition 객체는 스프링 컨테이너가 빈을 생성하고 관리하기 위해 사용하는 메타데이터를 포함합니다. 여기에는 다음과 같은 주요 속성들이 포함됩니다:
1. 빈 클래스 이름 (Bean Class Name):
⦁ 빈이 어떤 클래스의 인스턴스인지를 정의합니다. 스프링 컨테이너는 이 클래스 정보를 사용하여 빈의
인스턴스를 생성합니다.
2. 스코프 (Scope):
⦁ 빈의 범위를 정의합니다. 예를 들어, singleton, prototype, request, session 등의 스코프가 있습니다.
singleton 스코프는 빈의 단일 인스턴스가 애플리케이션 컨텍스트에 존재하도록 하고,
prototype 스코프는 요청할 때마다 새로운 인스턴스를 생성합니다.
3. 생성자 인자 값 (Constructor Arguments):
⦁ 빈이 생성될 때 생성자에 전달되는 인자들을 정의합니다. 이를 통해 스프링은 올바른 생성자를 호출하여
객체를 생성할 수 있습니다.
4. 프로퍼티 값 (Property Values):
⦁ 생성된 빈의 속성(property) 값을 설정하는데 사용됩니다.
이는 setter 메서드나 필드에 값을 주입하는 데 사용됩니다.
5. 의존성 (Dependencies):
⦁ 빈이 생성될 때 필요한 다른 빈에 대한 의존성을 정의합니다. 이를 통해 스프링은 필요한 다른 빈들을
먼저 생성하고, 이 빈에 주입할 수 있습니다.
6. 초기화 메서드 (Init Method):
⦁ 빈이 생성된 후 호출될 초기화 메서드를 정의합니다.
7. 소멸 메서드 (Destroy Method):
⦁ 빈이 컨테이너에서 제거될 때 호출될 메서드를 정의합니다.
예시: BeanDefinition 메타데이터 예시
@Configuration public class AppConfig { @Bean(initMethod = "init", destroyMethod = "destroy") public MyService myService() { MyService myService = new MyService("Hello, Spring!"); myService.setDependency(dependencyBean()); return myService; } @Bean public DependencyBean dependencyBean() { return new DependencyBean(); } }
위의 예시에서, myService 빈은 다음과 같은 메타데이터를 가지게 됩니다:
⦁ 빈 클래스 이름: MyService
⦁ 스코프: singleton (기본값)
⦁ 생성자 인자 값: 없음 (기본 생성자 사용)
⦁ 프로퍼티 값: setDependency 메서드를 통해 주입된 DependencyBean
⦁ 초기화 메서드: init
⦁ 소멸 메서드: destroy
⦁ 의존성: dependencyBean
이 모든 정보는 BeanDefinition 객체의 속성으로 캡슐화되며, 스프링 컨테이너는 이 정보를 사용하여 실제 빈 객체를 생성하고 관리합니다.
따라서, "해당 빈 정의에 캡슐화된 구성 메타데이터"는 바로 이 BeanDefinition 객체의 속성들에 저장된 정보들을 의미합니다. 이 정보들은 빈을 생성, 초기화, 주입, 관리하는 데 필요한 모든 것을 포함하고 있습니다.
XML 기반 구성 메타데이터를 사용하는 경우, 인스턴스화할 객체의 타입(또는 클래스)을 <bean/> 엘리먼트의 class 속성에 지정합니다. 이 class 속성(내부적으로는 BeanDefinition 인스턴스의 Class 속성)은 일반적으로 필수입니다. (예외 사항에 대해서는 Instantiation by Using an Instance Factory Method 및 Bean Definition Inheritance 을 참조하십시오.) Class 속성은 다음 두 가지 방법 중 하나로 사용할 수 있습니다:
- 일반적으로 컨테이너 자체가 생성자를 반사적으로 호출하여 Bean을 직접 생성하는 경우 생성될 Bean 클래스를 지정하는 것은 new 연산자를 사용하는 Java 코드와 다소 동일합니다.("반사적으로 호출한다"는 의미는 자바 리플렉션(Reflection) API를 사용하여 런타임에 클래스의 생성자를 호출하는 것을 말합니다. 즉, 컴파일 시점이 아닌 런타임 시점에 클래스의 메타데이터(예: 클래스, 생성자, 메서드, 필드 등)를 조사하고, 이를 통해 객체를 생성하거나 메서드를 호출하는 것을 의미합니다.)
- 컨테이너가 빈을 생성하기 위해 특정 클래스의 static 팩토리 메서드를 호출하는 조금은 일반적이지 않는 경우, 객체를 생성하기 위해 호출되는 static 팩토리 메서드가 포함된 실제 클래스를 지정합니다. static 팩토리 메서드 호출에서 리턴된 객체 타입은 동일한 클래스이거나 완전히 다른 클래스일 수 있습니다.
// MyService.java
public class MyService {
private String message;
// private 생성자
private MyService(String message) {
this.message = message;
}
// static 팩토리 메서드
public static MyService createInstance() {
return new MyService("Hello from MyService!");
}
public String getMessage() {
return message;
}
}
// AppConfig.java (스프링 설정 클래스)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return MyService.createInstance();
}
}
Nested class names
중첩 클래스에 대한 빈 정의를 구성하려면, 중첩 클래스의 바이너리 이름이나 소스 이름을 사용할 수 있습니다.
예를 들어, com.example 패키지에 SomeThing이라는 클래스가 있고, 이 SomeThing 클래스에 OtherThing이라는 정적 중첩 클래스가 있는 경우, 이들은 달러 기호($) 또는 점(.)으로 구분할 수 있습니다. 따라서 빈 정의의 class 속성 값은 com.example.SomeThing$OtherThing 또는 com.example.SomeThing.OtherThing이 됩니다.
Instantiation with a Constructor
1. 스프링 IoC 컨테이너의 범용성
- 모든 클래스 호환: 스프링 IoC 컨테이너는 대부분의 일반적인 클래스를 관리할 수 있습니다. 클래스를 스프링 빈으로 등록하기 위해 특별한 인터페이스를 구현하거나 특정 코딩 패턴을 따를 필요가 없습니다. 즉, 개발자가 작성한 대부분의 클래스는 스프링에서 사용 가능하며 호환됩니다.
2. 생성자 접근 방식
- 생성자를 통한 빈 생성: 스프링은 클래스를 빈으로 만들 때 생성자를 통해 객체를 생성할 수 있습니다. 이 경우, 특별한 요구사항이 없으면 기본 생성자가 필요하지 않지만, 특정 IoC 방식에서는 기본 생성자가 필요할 수 있습니다.
3. JavaBean 스타일 클래스
- JavaBean 선호: 많은 스프링 사용자는 디폴트 생성자(기본 생성자)와 설정자(setter), 접근자(getter) 메서드를 가진 JavaBean 스타일의 클래스를 선호합니다. 이는 클래스의 속성들을 설정하고 가져올 수 있는 메서드가 있다는 뜻입니다.
- JavaBean이 아니어도 관리 가능: 스프링은 JavaBean 사양을 따르지 않는 클래스도 관리할 수 있습니다. 예를 들어, 초기화 메서드나 설정자 메서드 없이 생성자만을 사용하는 클래스도 관리 가능합니다.
4. 특이한 클래스 관리
- non-bean 스타일 클래스: 스프링 컨테이너는 일반적인 JavaBean 스타일이 아닌 특이한(non-bean) 스타일의 클래스도 관리할 수 있습니다. 예를 들어, 레거시 시스템에서 사용되는 특정 클래스를 스프링 컨테이너가 관리할 수 있습니다.
5. Java 기반 구성 메타데이터 예시
- 스프링에서는 XML 대신 Java 코드로 빈 설정을 할 수 있습니다. 이때 @Configuration과 @Bean 어노테이션을 사용하여 구성 메타데이터를 정의합니다.
- 이 설정은 스프링이 관리할 객체들을 정의하고, 어떻게 생성하고 초기화할지를 지정하는 방법입니다.
위 내용을 통해 스프링이 얼마나 유연하게 다양한 유형의 클래스와 객체를 관리할 수 있는지 이해할 수 있습니다.
1. JavaBean 스타일 클래스 관리 예시
// JavaBean 스타일의 클래스
public class MyBean {
private String name;
private int age;
// 디폴트 생성자
public MyBean() {
}
// 접근자와 설정자 (Getter와 Setter)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// AppConfig.java (스프링 설정 클래스)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
myBean.setName("John Doe");
myBean.setAge(30);
return myBean;
}
}
위 예시에서 MyBean은 JavaBean 스타일로 작성된 클래스이며, 스프링 IoC 컨테이너에 의해 관리됩니다. AppConfig 클래스는 @Bean 메서드를 통해 MyBean의 인스턴스를 생성하고 속성을 설정합니다.
2. JavaBean 사양을 따르지 않는 클래스 관리 예시
// JavaBean 사양을 따르지 않는 클래스
public class LegacyConnectionPool {
private String connectionString;
// 디폴트 생성자가 없음
public LegacyConnectionPool(String connectionString) {
this.connectionString = connectionString;
}
// JavaBean 스타일의 접근자와 설정자가 없음
public void connect() {
System.out.println("Connecting to: " + connectionString);
}
}
// AppConfig.java (스프링 설정 클래스)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public LegacyConnectionPool legacyConnectionPool() {
return new LegacyConnectionPool("jdbc:legacy-db://localhost:3306/mydb");
}
}
이 두 번째 예시에서 LegacyConnectionPool은 JavaBean 스타일이 아닌 클래스로, 디폴트 생성자가 없고, 설정자(setter)와 접근자(getter) 메서드도 없습니다. 그럼에도 불구하고 스프링은 이 클래스를 관리할 수 있으며, AppConfig 클래스에서 @Bean 메서드를 사용해 이를 스프링 컨텍스트에 등록할 수 있습니다.
요약
- JavaBean 스타일 클래스는 스프링에서 가장 일반적으로 사용되며, 디폴트 생성자와 설정자/접근자를 가집니다.
- JavaBean 스타일이 아닌 클래스도 스프링에서 관리할 수 있으며, 이 경우 스프링은 클래스의 특성에 맞는 방법으로 빈을 생성하고 관리합니다.
- Java 기반 구성 메타데이터는 @Configuration과 @Bean 어노테이션을 사용하여 스프링 컨테이너에서 사용할 빈을 정의합니다.
생성자에 아규먼를 제공하는 메커니즘(필요한 경우)과 객체가 생성된 후 객체 인스턴스 속성을 설정하는 방법에 대한 자세한 내용은 Injecting Dependencies을 참조하십시오.
다음은 자바 기반 구성 메타데이터를 사용하여 빈을 생성하는 일반적인 예제는 다음과 같습니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public ExampleBean exampleBean() {
return new ExampleBean();
}
@Bean(name = "anotherExample")
public ExampleBeanTwo exampleBeanTwo() {
return new ExampleBeanTwo();
}
}
위 구성 클래스를 사용하여 ApplicationContext를 다음과 같이 초기화할 수 있습니다.
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ExampleBean exampleBean = context.getBean(ExampleBean.class);
ExampleBeanTwo exampleBeanTwo = (ExampleBeanTwo) context.getBean("anotherExample");
// ExampleBean 및 ExampleBeanTwo 사용
exampleBean.doSomething();
exampleBeanTwo.doSomethingElse();
}
}
위 예제에서는 AppConfig라는 @Configuration 클래스를 정의하고, @Bean 어노테이션을 사용하여 빈을 생성합니다. 그런 다음 AnnotationConfigApplicationContext를 사용하여 Spring 컨테이너를 초기화하고, 빈을 가져와 사용할 수 있습니다.
참고:
생성자 아규먼트의 경우, 컨테이너는 여러 오버로드된 생성자 중에서 해당 생성자를 선택할 수 있습니다. 그러나 애매함을 피하기 위해 생성자 시그니처는 가능한 한 단순하게 유지하는 것이 좋습니다.
Instantiation with a Static Factory Method
xml 기반 구성 메타데이터에서 static 팩토리 메소드를 사용하여 생성하는 Bean을 정의할 때 class 속성을 사용하여 static 팩토리 메소드가 포함된 클래스를 지정하고, 팩토리 메소드 자체의 이름을 지정하려면 factory-method라는 속성을 사용하십시오. 나중에 설명하는 선택적 아규먼트를 사용하여 이 메서드를 호출하고 라이브 객체를 반환할 수 있어야 하며, 이후 이 객체는 생성자를 통해 생성된 것처럼 처리됩니다. 이러한 Bean 정의의 용도 중 하나는 레거시 코드에서 static 팩토리 메소드를 호출하는 것입니다.
다음 빈 정의는 팩토리 메서드를 호출하여 빈을 생성할 것임을 지정합니다. 이 빈 정의는 리턴된 객체의 타입(클래스)을 지정하지 않고, 대신 팩토리 메서드를 포함하는 클래스를 지정합니다. 이 예제에서 createInstance() 메서드는 정적 메서드여야 합니다. 다음 예는 팩토리 메서드를 지정하는 방법을 보여줍니다:
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
다음 코드는 위 xml 기반 구성 메타데이터와 동일한 구성 정보를 가지는 자바 기반 구성 메타데이터입니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public ClientService clientService() {
return ClientService.createInstance();
}
}
다음 예제는 앞서 설명한 빈 정의와 함께 사용할 수 있는 클래스를 보여줍니다:
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
팩토리 메서드에 (선택적) 아규먼트를 제공하고, 객체가 팩토리에서 리턴된 후 객체 인스턴스 속성을 설정하는 메커니즘에 대한 자세한 내용은 " Dependencies and Configuration in Detail "을 참조하십시오.
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ClientService clientService = context.getBean(ClientService.class);
clientService.doSomething(); // 예시 메서드 호출
}
}
Note
팩토리 메서드 아규먼트의 경우, 컨테이너는 동일한 이름의 여러 오버로드된 메서드 중에서 해당 메서드를 선택할 수 있습니다. 그러나 애매함을 피하기 위해 팩토리 메서드 시그니처는 가능한 한 단순하게 유지하는 것이 좋습니다.
Tip
팩토리 메서드 오버로딩과 관련된 일반적인 문제 사례는 mock 메서드의 많은 오버로드가 있는 Mockito입니다. 가능한 가장 구체적인 mock 변형을 선택하십시오:
<bean id="clientService" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg type="java.lang.Class" value="examples.ClientService"/>
<constructor-arg type="java.lang.String" value="clientService"/>
</bean>
Instantiation by Using an Instance Factory Method
static 팩토리 메소드를 통한 인스턴스화와 유사하게, instance 팩토리 메소드를 사용한 인스턴스화는 컨테이너에서 특정(아래 예에서는 serviceLocator 빈)Bean의 non-static 메소드를 호출하여 특정 Bean(아래 예에서는 clientSevice 빈)을 생성합니다. 이 메커니즘을 사용하려면 class 속성을 비워두고 factory-bean 속성에서 객체를 생성하기 위해 호출될 인스턴스 메서드가 포함된 현재 컨테이너에 등록된 Bean(serviceLocator) 이름을 지정합니다. factory-method 속성을 사용하여 팩토리 메소드 자체의 이름을 설정합니다. 다음 예에서는 이러한 Bean을 구성하는 방법을 보여줍니다.
<!-- the factory bean, which contains a method called createClientServiceInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
다음 예에서는 해당 팩토리 빈 클래스를 보여줍니다.
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
package examples;
public interface ClientService {
void doSomething();
}
public class ClientServiceImpl implements ClientService {
@Override
public void doSomething() {
System.out.println("ClientService is doing something");
}
}
위 예제를 자바 기반 구성 메타데이터로 변경하면 다음과 같습니다.
자바 기반 구성 메타데이터를 만듭니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public DefaultServiceLocator serviceLocator() {
return new DefaultServiceLocator();
}
@Bean
public ClientService clientService() {
return serviceLocator().createClientServiceInstance();
}
}
마지막으로, 이 구 클래스를 사용하여 ApplicationContext를 초기화하고 빈을 가져오는 코드를 작성합니다:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import examples.ClientService;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ClientService clientService = context.getBean(ClientService.class);
// ClientService 사용
clientService.doSomething();
}
}
하나의 팩토리 빈 클래스가 여러 팩토리 메서드를 가질 수도 있습니다. 다음 예제에서 보여줍니다:
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
<bean id="accountService"
factory-bean="serviceLocator"
factory-method="createAccountServiceInstance"/>
다음 예제는 해당 클래스를 보여줍니다:
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
위 예제를 자바 기반 구성 메타데이터를 사용하는 코드들은 다음과 같습니다.
public interface AccountService {
void performAction();
}
public class AccountServiceImpl implements AccountService {
@Override
public void performAction() {
System.out.println("AccountService is performing an action");
}
}
자바 기반 구성 메타데이터 클래스를 다음과 같이 작성합니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public DefaultServiceLocator serviceLocator() {
return new DefaultServiceLocator();
}
@Bean
public ClientService clientService() {
return serviceLocator().createClientServiceInstance();
}
@Bean
public AccountService accountService() {
return serviceLocator().createAccountServiceInstance();
}
}
main 메소드는 다음과 같습니다.
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import examples.ClientService;
import examples.AccountService;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ClientService clientService = context.getBean(ClientService.class);
AccountService accountService = context.getBean(AccountService.class);
// ClientService 및 AccountService 사용
clientService.doSomething();
accountService.performAction();
}
}
이 접근 방식은 팩토리 빈 자체가 의존성 주입(DI)을 통해 관리되고 구성될 수 있음을 보여줍니다. 자세한 내용은 " Dependencies and Configuration in Detail "을 참조하십시오.
Note:
Spring 문서에서 "factory bean"은 Spring 컨테이너에 구성된 빈으로, 인스턴스나 정적 팩토리 메소드를 통해 객체를 생성하는 빈을 의미합니다. 대조적으로, FactoryBean(대문자 사용에 주의)은 Spring 특정 FactoryBean 구현 클래스를 참조합니다.
Determining a Bean’s Runtime Type
특정 bean의 런타임 타입을 결정하는 것은 간단하지 않습니다. bean 메타데이터 정의에서 지정된 클래스는 초기 클래스 참조일 뿐이며, 잠재적으로 선언된 팩토리 메서드와 결합되거나 FactoryBean 클래스일 경우 빈의 다른 런타임 타입으로 이어질 수 있습니다. 또는 인스턴스 레벨 팩토리 메서드의 경우에는 (지정된 factory-bean 이름을 통해 해결되므로) 전혀 설정되지 않을 수도 있습니다. 추가적으로, AOP 프록시가 bean 인스턴스를 인터페이스 기반 프록시로 래핑할 수 있으며, 이 경우 타겟 빈의 실제 타입이 제한된 인터페이스로만 노출됩니다.
빈 메타데이터 정의에서 지정된 클래스가 팩토리 메서드와 결합된 예제를 명확히 보여주는 코드를 작성해보겠습니다.
다음은 빈 메타데이터 정의에서 지정된 클래스가 팩토리 메서드와 결합된 예제를 보여주는 코드입니다.
먼저, DefaultServiceLocator 클래스를 정의합니다:
package examples;
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
// 팩토리 메서드
public ClientService createClientServiceInstance() {
return clientService;
}
}
ClientService 인터페이스를 정의합니다.
// ClientService 인터페이스
package examples;
public interface ClientService {
void doSomething();
}
ClientService 인터페이스를 구현한 ClientServiceImpl 클래스를 정의합니다.
// ClientService 구현 클래스
package examples;
public class ClientServiceImpl implements ClientService {
@Override
public void doSomething() {
System.out.println("ClientServiceImpl is doing something");
}
}
이제 Spring 구성 클래스를 작성합니다:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public DefaultServiceLocator serviceLocator() {
return new DefaultServiceLocator();
}
@Bean
public ClientService clientService() {
// serviceLocator 빈의 createClientServiceInstance 팩토리 메서드를 호출하여 빈 생성
return serviceLocator().createClientServiceInstance();
}
}
이 설정 클래스는 DefaultServiceLocator 클래스의 팩토리 메서드 createClientServiceInstance를 사용하여 ClientService 빈을 생성합니다. 이제, 이 구성 클래스를 사용하여 ApplicationContext를 초기화하고 빈을 가져오는 코드를 작성합니다:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import examples.ClientService;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// ClientService 빈을 가져옴
ClientService clientService = context.getBean(ClientService.class);
clientService.doSomething(); // ClientServiceImpl is doing something 출력
}
}
위 코드에서는 AppConfig라는 @Configuration 클래스를 정의하고, @Bean 어노테이션을 사용하여 serviceLocator와 clientService 빈을 생성합니다. clientService 빈은 serviceLocator 빈의 createClientServiceInstance 팩토리 메서드를 호출하여 생성됩니다. 이는 빈 메타데이터 정의에서 지정된 클래스가 팩토리 메서드와 결합된 경우를 보여줍니다.
특정 빈의 실제 런타임 타입을 알아내는 권장 방법은 지정된 빈 이름에 대해 BeanFactory.getType 호출을 사용하는 것입니다. 이는 위의 모든 경우를 고려하여 동일한 빈 이름에 대해 BeanFactory.getBean 호출이 반환할 객체의 타입을 반환합니다.
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.beans.factory.BeanFactory;
import examples.ClientService;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// ClientService 빈을 가져옴
ClientService clientService = context.getBean(ClientService.class);
clientService.doSomething(); // ClientServiceImpl is doing something 출력
// BeanFactory를 사용하여 빈의 실제 런타임 타입을 알아냄
BeanFactory beanFactory = context.getAutowireCapableBeanFactory();
Class<?> clientServiceType = beanFactory.getType("clientService");
System.out.println("Runtime type of 'clientService' bean: " + clientServiceType.getName());
}
}
'Spring Framework > Spring IoC' 카테고리의 다른 글
Spring IoC 컨테이너 이해하기: 제5편 (0) | 2024.08.13 |
---|---|
Spring IoC 컨테이너 이해하기: 제4편 (1) | 2024.08.12 |
스프링 프레임워크의 의존성 주입 - 유연한 애플리케이션 설계의 핵심 (0) | 2024.08.08 |
Spring IoC 컨테이너 이해하기: 제3편 (0) | 2024.08.08 |
Spring IoC 컨테이너 이해하기: 제1편 (0) | 2024.08.06 |