Spring Framework 6.2 문서 읽고 이해하기 ... IOC Container (2)
IoC Container 찍먹 해본 지난 글에 이어서 이번에는 Bean을 알아보자.
Spring Framework 6.2 문서 읽고 이해하기 ... IOC Container (1)
현재 정산 백엔드 직군으로 일하고 있고 사용하는 기술은 Spring Boot와 Kotlin이다. (사람마다 깊이에 대한 기준은 다르지만) Spring을 깊은 이해 없이 활용 가능한 정도로 공부한 후 사용하다가 문제
dol9.tistory.com
IoC Container는 한개 이상의 빈을 관리하는데, 이 빈들은 XML <bean /> 같은 메타데이터 설정을 통해 생성된다.
빈 정의는 아래 정보를 BeanDefinition 객체에 담아놓는다.
- 패키지 포함 클래스 이름: 빈의 실제 구현 클래스
- 빈의 행위: 컨테이너에서 빈이 어떻게 동작하는지에 대한 상태 정보 (Scope, 라이프사이클 콜백 등등)
- 빈이 실행되기 위해 참조하는 다른 빈: 참조하는 다른 빈을 collaborators 또는 depdencies라고 부른다
- 새롭게 생성되는 객체에 설정 정보: 예를 들어 빈에서 커넥션 풀을 관리하기 위해 사용되는 풀의 크기
이 메타데이터는 각각의 빈 정의를 구성하는 속성으로 변환된다. 속성들은 다음과 같다.
Property | Explained in ... |
Class | 빈 인스턴스화 |
Name | 빈 이름 |
Scope | 빈 Scope |
Constructor arguments | 의존성 주입 |
Properties | 의존성 주입 |
Autowiring mode | Autowiring 협력자 |
Lazy initialization mode | 게으른 빈 인스턴스화 |
Initialization method | 초기화 콜백 |
Destruction method | 소멸자 콜백 |
ApplicationContext에는 빈 생성에 필요한 빈 정의 말고도, registerSingleton(..), registerBeanDefinition(..)을 이용해서
외부에서 생성한 객체를 빈으로 등록할 수도 있다.
하지만 있다는것만 알아두고 어플리케이션 개발할 때 쓰진 말자.
빈 이름
모든 빈은 한 개 이상의 식별자를 가지고 있다.
대개 한개의 식별자만 사용하고 식별자가 더 필요한 경우 별칭을 이용한다.
XML로 메타데이터를 설정한 경우 id 또는 name 속성을 이용해 식별자를 지정할 수 있다.
관습적으로 알파벳과 숫자를 사용하고 특수문자는 사용 가능하다.
별칭을 만들고 싶다면 name속성에 콤마(,), 세미콜론(;), 공백( )을 구분자로 여러 개를 입력하면 된다.
그리고 id 속성은 xsd:string 타입으로 정의됐지만 고유성은 IoC 컨테이너에서만 강제되고, XML parser에서는 강제되지 않는다.
(XML 쓰는 중에는 중복인지 아닌지 알 수 없다는 뜻)
name이나 id가 필수는 아닌데, 둘다 명시하지 않는 경우 자동으로 고유한 이름을 만든다.
하지만 빈 이름으로 참조하거나 XML에서 ref 속성 또는 서비스 로케이터 패턴을 사용한다면 반드시 이름을 지정해야 한다.
빈 이름 규칙
자바에서 멤버변수의 이름 규칙과 동일하게 소문자로 시작하고 camelCase 형식을 쓴다.
이름이 없는 경우 java.beans.Introspector.decapitalize 를 이용해서 자동으로 생성한다.
https://docs.oracle.com/javase/8/docs/api/java/beans/Introspector.html#decapitalize-java.lang.String-
빈 정의 밖에서 빈 별칭 정의하기
앞에서 id 하나, name 여러개 조합으로 여러 이름을 정의할 수 있다고 했다.
하지만 alias 속성을 이용해서 별칭만 정의할 수 있다.
별칭을 이용하면 어플리케이션의 각 컴포넌트가 컴포넌트에 특화된 이름으로 참조하는 상황에 유용하게 사용할 수 있다.
또한 동일한 빈에 대해서 서로 다른 시스템이 사용한다고 할 때 별칭을 사용하면 네임스페이스 느낌으로 관리가 된다.
※ myApp-dataSource, subsystemA-dataSource, subsystemB-dataSource 모두 같은 빈이다.
<alias name="fromName" alias="toName"/>
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Java-configuration
XML이 아니라 Java configuration을 사용하고 있다면 @Bean annotation으로 별칭을 설정할 수 있다.
자세한 내용은 Using the @Bean Annotation 을 보자
빈 인스턴스화
빈 정의(Bean definition)는 하나 이상의 객체를 생성하는 레시피다.
컨테이너는 생성 요청을 받으면 빈 정의 레시피를 살펴보고, 빈 정의로 캡슐화된 메타데이터 설정을 사용하여
객체를 생성 또는 가져옵니다.
XML 메타데이터 설정을 사용한다면 <bean />의 class 속성을 사용하여 인스턴스화시킬 클래스를 지정한다.
class 속성은 일반적으로 필수 값인데 예외 상황이 있다. ex: Factory Method 또는 Bean 상속
- 일반적으로 자바 코드의 new 연산자 호출하듯이 container에서 생성자를 직접 호출해서 빈을 생성한다.
- 컨테니어가 static 팩토리 메소드를 호출해서 빈 생성하는 방법은 덜 일반적이다.
static 팩토리 메소드 호출 결과가 동일한 클래스일 수도 있고 다른 클래스일 수도 있다.
생성자를 이용한 인스턴스화
Spring IoC 컨테이너는 어떠한 클래스라도 관리할 수 있다. 다수의 Spring 유저는 기본 생성자를 이용해서
Bean을 만들고 setter, getter로 프로퍼티 채우는 방식을 선호한다. (예전에 써서 그런가? 이젠 생성자 주입을 선호)
XML 메타데이터 설정을 쓴다면 아래와 같이 빈을 정의할 수 있다.
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
생성자 주입을 좀 더 알고 싶다면 Dependency Injection을 참고하자
Static Factory 메소드를 이용한 인스턴스화
static factory 메소드로 빈을 정의하기 위해서는 clsss 속성에 정의한 클래스에 static factory method 이름이
factory-method로 추가해주면 된다.
<bean id="clientService" class="examples.ClientService"
factory-method="createInstance"/>
앞에서 정의한 Bean Definition을 동작하기 위한 클래스 예시는 다음과 같다.
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
한 클래스가 여러 static factory 메서드를 가지고 여러 타입을 리턴할 수도 있다. (개인적으로 있다 정도만 알아두기로 했다.)
보다 자세한 static factory 메소드를 알고 싶다면 Dependencies and Configuration in Detail을 참고하자