[TIL] Spring Core 1.3

WonJune Kang·2021년 8월 22일
0

spring-core

목록 보기
2/2
post-thumbnail

1.3. Bean Overview

Spring IoC 컨테이너는 하나 이상의 빈을 관리한다. 이러한 빈은 컨테이너에 제공하는 Configuration Meta-data로 생성된다.
컨테이너 자체 내에서는 이러한 빈 정의는 다음 메타데이터를 포함하는 BeanDefinition 객체로 표시된다.

- A package-qualified class name: 일반적으로 정의되는 빈의 실제 구현 클래스
- Bean이 컨테이너에서 작동하는 방식을 나타내는 Bean Configuration 요성 (Scope, lifecycle callbacks 등)
- 다른 Bean에 대한 참조는 Bean이 작업을 수행하는 데 필요하다. 이러한 참조는 또한 collaborators 또는 dependencies라 한다.
- 새로생성된 개체에서 설정할 기타 Configuration 설정 (예: 풀의 크기 제한 또는 연결 풀을 관리하는 Bean에서 사용할 연결 수)

특정 빈을 생성하는 방법에 대한 정보를 포함하는 빈정의 외에도 ApplicationContext 구현은 컨테이너 외부에서 사용자에 의해 생성된 기존 객체의 등록도 허용한다.
이것은 BeanFactory DefaultListableBeanFactory 구현을 반환되는 getBeanFactory() 메소드를 통해 ApplicationContext의 BeanFactory 액세스하여 수행된다.
DefaultListableBeanFactory는 registerSingletone(..) 및 registerBeanDefinition(..) 메소드를 통해 이 등록을 지원한다. 그러나 일반적인 응용 프로그램은 일반 빈 정의 메타데이터를 통해 정의된 빈으로만 작동한다.

Bean 메타데이터 및 수동으로 제공되는 싱글톤 인스턴스는 가능한 한 빨리 등록해야 컨테이너가 autowiring 및 기타 내부 검사 단계에서 이에 대해 적절하게 추론할 수 있다.
기존 메타데이터 및 기존 싱글톤 인스턴스를 재정의하는 것은 어느 정도 지원되지만 런타임 시 새 Bean 등록(팩토리에 대한 실시간 액세스와 동시에)은 공식적으로 지원되지 않으며 동시에 액세스 예외, Bean 컨테이너의 일관성 없는 상태 또는 둘 다를 가질 수 있다.

1.3.1. Naming Beans

모든 빈에는 하나 이상의 식별자가 있다. 이러한 식별자는 Bean을 호스팅하는 컨테이너 내에서 유니크해야한다. 빈에는 일반적으로 하나의 식별자만 있다. 그러나 둘 이상이 필요한 경우 추가 항목은 별칭으로 간주될 수 있다.

!! Bean의 name이나 id를 무조건 제공할 필욘 없다!
name이나 id를 명시적으로 제공하지 않아도 컨테이너가 해당 빈에 대해 식별자를 생성해준다.
하지만 다른 bean에서의 사용이 어려워진다.

Bean Naming Conventions (Bean 명명 규칙)
Bean의 이름을 지정할 때 인스턴스 필드 이름에 대해 표준 Java 규칙을 사용해야 한다.
예) accountMananer, accountService, userDao, loginController 등

빈의 이름을 일관되게 지정하면 구성을 더 쉽게 읽고 이해할 수 있다.
또한 Spring AOP를 사용한다면 이름으로 관련된 빈들의 집합에 어드바이스를 적용할 때 많은 도움이 된다.

classpath에서 컴포넌트 스캐닝을 통해 Spring은 앞에서 설명한 규칙에 따라 이름 없는 컴포넌트에 대한 빈 이름을 생성한다.
기본적으로 간단한 클래스 이름을 취하고 초기 문자를 소문자로 시작한다.
두 개 이상의 문자가 있고 첫 번째와 두 번째 문자가 모두 대문자인 특수한 경우에는 원래 대소문자가 유지된다.
java.beans.Introspector.decapitalize에 의해 정의된 것과 동일한 규칙이다.

Bean 정의 외부에서 Bean 별칭 지정

<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>

Java-configuration

Java 구성을 사용하는 경우 @Bean Annotation을 사용하여 별칭을 제공할 수 있다.

1.3.2. Instantiating Beans

빈 정의는 본질적으로 하나 이상의 객체를 생성하기 위한 레시피로 보면 된다.
컨테이너는 요청 시 명명된 빈에 대한 레시피를 살펴보고 해당 빈 정의에 의해 캡슐화된 구성 메타 데이터를 사용허여 실제 객체를 생성(또는 획득)한다.

Class 속성을 사용하는 두 가지 방법
- 컨테이너 자체가 생성자를 Reflection하여 호출하여 Bean을 직접 생성(Java 코드와 비슷한 개념)
- 객체를 생성하기 위해 정적 팩토리 메소드를 이용한다.

Instantiation With a Constructor (생성자를 사용한 인스턴스화)

Spring IoC 컨테이너는 관리하고자 하는 거의 모든 클래스를 관리할 수 있다.
대부분의 Spring 사용자는 기본 생성자와 컨테이너의 속성을 따라 모델링된 적절한 설정자 및 setter, getter만 있는 JavaBean을 선호한다.
하지만, JavaBean 명세를 따르지 않는 레거시 연결 풀을 사용해야 하는 경우도 Spring에서 관리할 수 있다.

JavaBean 규약

1. 패키지
자바빈은 기본 패키지 이외의 특정 패키지에 속해 있어야 한다.
javaBean 규약을 따르는 예: `com.app.bean.BeanSample`
javaBean 규약을 따르지 않는 예: `(default package) BeanSample`
2. 기본 생성자가 존재해야 한다.
package com.app.bean;

public class BeanEx {
	public BeanEx() {}
}
3. 멤버변수의 접근제어자는 private로 선언되어야 한다.
4. 멤버변수에 접근 가능한 getter, setter메소드가 존재해야 한다.
5. getter, setter는 접근자가 public해야 한다.
6. 멤버변수가 배열인 경우 getter, setter 구현방법
package com.app.bean;

public class BeanEx {
	private int[] nums;
	public BeanEx() {}
	// 첫 번째 방법
	public int[] getNums() { return nums; }
	public void setNums(int[] nums) { this.nums = nums; }

	// 두 번째 방법 - 배열의 일부값만 설정 또는 가져오는 방법
	public int getNums(int index) { return nums[index]; }
	public void setNums(int num, int index) { this.nums[index] = num; }
}
7. 직렬화 되어 있어야 한다.

Instantiation With a Static Factory Method (static 팩토리 메소드를 이용한 인스턴스화)

정적 팩토리 메소드로 Bean을 생성할 경우, 생성자를 통해 생성된 것처럼 처리된다.
아래 빈 정의는 팩토리 메소드를 호출하여 빈을 생성하도록 지정한다.
정의는 반환된 객체의 유형(클래스)을 지정하지 않고 팩토리 메소드를 포함하는 클래스만 지정한다.
이 예에서 createInstance() 메소드는 정적 메소드여야 한다.

public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

    public static ClientService createInstance() {
        return clientService;
    }
}

Instantiation by Using an Instance Factory Method (인스턴스 팩토리 메소드를 이용한 인스턴스화)

컨테이너에서 기존 Bean의 비정적 메소드를 호출하여 새 Bean을 생성한다.

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

하나의 팩토리 클래스가 둘 이상의 팩토리 메소드를 보유한 경우

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;
    }
}

이러한 접근 방식을 봤을 때, 팩토리 빈 자체가 종속성 주입(DI)를 통해 관리 및 구성될 수 있음을 보여준다.

Determining a Bean's Runtime Type (Bean의 런타임 유형 결정)

특정 Bean의 런타임 유형은 결정하기 쉽지 않다.
Bean Meta-data 정의에서 지정된 클래스는 초기 클래스 참조일 뿐이며 잠재적으로 선언된 팩토리 메소드와 결합되거나 빈의 다른 런타임 유형으로 이어질 수 있는 FactoryBean 클래스가 될 수 있다.
또는 인스턴스 수준의 팩토리 메소드의 경우 전혀 설정되지 않을 수도 있다.
또한 AOP 프록시는 대상 빈의 실제 유형에 대한 노출을 제한함으로써 인터페이스 기반 프록시로 빈 인스턴스를 감쌀 수 있다.

profile
Excelsior!

0개의 댓글