Spring Framework 공식 문서 읽기 - Core 1.1 ~ 1.3

김강연·2022년 9월 22일
0
post-thumbnail

공식 문서 링크: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-introduction

!!!읽기 전 당부사항

아래 번역문은 Google 번역으로 처리 후, 제 주관대로 자연스럽게 읽힐 수 있도록 변경하거나, 실제 프로그래밍 분야에서 쓰인 부분들을 직접 검색하여 자연스럽게 변경한 부분들이 포함되어 있습니다. 자연스러운 번역이 아니라고 생각드는 경우 원문을 함께 실은 경우가 있지만, 정확한 지식 습득을 위해서는 원문과 비교하며 읽으시는 것을 권장드립니다.

1.1. Spring IoC 컨테이너와 Beans에 대한 소개

이 장에서는 IoC(Inversion of Control) 원리에 대한 Spring Framework 구현을 다룹니다. IoC는 DI(종속성 주입)라고도 알려져 있습니다. 객체가 오직 생성자 argument, factory 메서드 argument 또는 factory 메서드에서 생성되거나 반환된 후 객체 인스턴스에 설정된 속성(property)을 통해서만 객체가 종속성(즉, 함께 작업하는 다른 객체)을 정의하는 프로세스입니다. 그런 다음 컨테이너는 bean을 생성할 때 이러한 종속성(dependency)을 주입합니다. 이 프로세스는 근본적으로 직접적인 클래스 생성이나 Service Locator 패턴과 같은 메커니즘을 사용하여 dependencies의 인스턴스화 또는 위치를 제어하는 bean 자체의 반대(따라서 이름이 Inversion of Control)입니다.

org.springframework.beans
org.springframework.context
두 패키지는 Spring Framework의 IoC 컨테이너의 기반입니다. BeanFactory 인터페이스는 모든 유형의 객체를 관리할 수 있는 고급 구성 메커니즘을 제공합니다. ApplicationContext는 BeanFactory의 서브(자식) 인터페이스입니다. ApplicationContext는 아래 목록을 보탭니다.

  • Spring의 AOP 기능과의 더 쉬운 통합
  • 메시지 리소스 처리(국제화에 사용)
  • 이벤트 발행
  • 웹 어플리케이션에서의 사용을 위한 WebApplicationContext와 같은 Application layer의 특정 컨텍스트.

요약하자면, BeanFactory는 구성 프레임워크와 기본 기능을 제공하고 ApplicationContext는 더 많은 기업 특화적인 기능을 추가합니다. ApplicationContext는 BeanFactory의 완전한 상위 집합(BeanFactory의 기능을 전부 포함한다는 의미)이며 이 장에서 Spring의 IoC 컨테이너에 대한 설명에서 독점적으로 사용됩니다. ApplicationContext 대신 BeanFactory를 사용하는 방법에 대한 자세한 내용은 1.16 The BeanFactory API를 다루는 섹션을 참조하십시오.

Spring에서, 어플리케이션의 중추를 구성하고 Spring IoC 컨테이너에 의해 관리되는 객체를 bean이라고 합니다. bean은 Spring IoC 컨테이너에 의해 인스턴스화되고, 조립되고, 그리고 관리되는 객체입니다. 그 외에는 bean은 단순히 어플리케이션에 있는 많은 객체 중 하나입니다. bean과, bean들 간의 종속성은 컨테이너에 의해 사용되는 구성 메타데이터(configuration metadata)에 반영됩니다.

1.2. Container 개요

org.springframework.context.ApplicationContext 인터페이스는 Spring IoC 컨테이너를 나타내며, bean의 인스턴스화, 구성 및 bean의 조립을 담당합니다. 컨테이너는 구성 메타데이터를 읽음으로써 어떤 객체를 인스턴스화하거나, 구성 및 조립할지에 대한 설명을 얻습니다. 구성 메타데이터는
XML, Java Annotation 또는 Java code로 표시됩니다. 이를 통해 어플리케이션을 구성하는 객체와 이러한 객체 간의 풍부한 상호 의존성을 표현할 수 있습니다.

ApplicationContext 인터페이스의 몇몇 구현이 Spring과 함께 제공됩니다. 독립적으로 실행되는 어플리케이션에서는, ClassPathXmlApplicationContext 또는 FileSystemXmlApplicationContext의 인스턴스를 생성하는 것이 일반적입니다. XML은 구성 메타데이터를 정의하는 전통적인 형식이었던 반면에, 이러한 추가 메타데이터 형식에 대한 지원을 선언적으로 활성화하기 위해 소량의 XML 구성을 제공하여 컨테이너에 메타데이터 형식으로 Java Annotation 또는 code를 사용하도록 지시할 수 있습니다.

대부분의 어플리케이션 시나리오에서 명시적인 사용자 코드는 Spring IoC 컨테이너의 1개 이상의 인스턴스를 인스턴스화하는 데 필요하지 않습니다. 예를 들어, 웹 어플리케이션 시나리오에서, 응용 프로그램의 web.xml 파일에 있는 boilerplate web descriptor XML 8 line 정도면 일반적으로 충분합니다(웹 어플리케이션을 위한 편리한 ApplicationContext 인스턴스화 참조). Eclipse용 Spring 도구(Eclipse 기반 개발 환경)를 사용하는 경우 몇 번의 마우스 클릭 또는 키 입력으로 이 boilerplate configuration을 쉽게 만들 수 있습니다.

Boilerplate code란?
1. 모든 코드를 작성하기 위해 항상 필요한 부분
2. 최소한의 변경으로 여러곳에서 재사용되며, 반복적으로 비슷한 형태를 띄는 코드

아래 도해(diagram)는 Spring이 작동하는 방식에 대한 상위 레벨에서의 측면을 보여줍니다. ApplicationContext가 생성되고 초기화된 후 완전히 구성되어 실행 가능한 시스템(또는 어플리케이션)을 갖기 위해, ApplicationContext가 생성되고 초기화된 이후 어플리케이션 클래스들은 구성 메타데이터와 결합된다.

1.2.1 Configuration Metadata

앞의 도해(diagram)에서 볼 수 있듯이, Spring IoC 컨테이너는 구성 메타데이터(configuratoin metadata) 형식을 사용합니다. 이 구성 메타데이터는 어플리케이션 개발자로서 Spring 컨테이너에게 어플리케이션의 객체를 인스턴스화, 구성 및 조립하도록 지시하는 방법을 나타냅니다.

구성 메타데이터는 전통적으로 간단하고 이해하기 쉬운 XML 형식으로 제공되며, XML 형식은 이 장의 대부분이 Spring IoC 컨테이너의 주요 개념과 기능을 전달하는 데 사용합니다.

Note
XML 기반 메타데이터가 유일하게 허용되는 구성 메타데이터 형식은 아닙니다. Spring IoC 컨테이너는 이 구성 메타데이터가 실제로 작성되는 형식과 완전히 분리되어 있습니다. 요즘에는, 많은 개발자들이 그들의 Spring 어플리케이션을 위해 1.12 Java-based configuration을 선택합니다.

For information about using other forms of metadata with the Spring container, see:
Spring 컨테이너에서 다른 형식의 메타데이터를 사용하기 위한 정보는, 다음을 보세요:

  • 1.9 Annotation-based configuration: Spring 2.5는 annotation 기반 구성 메타데이터에 대한 지원을 도입했습니다.

  • 1.12 Java-based configuration: Spring 3.0부터 Spring JavaConfig 프로젝트에서 제공하는 많은 기능이 핵심 Spring Framework의 일부가 되었습니다. 따라서 XML 파일 대신 Java를 사용하여 어플리케이션 클래스 외부에 Bean을 정의할 수 있습니다. 이러한 새로운 기능을 사용하려면 @Configuration, @Bean, @Import@DependsOn annotation들을 참조하세요.

Spring 구성은 컨테이너가 관리해야 하는 최소 1개 이상의 bean 정의로 이루어집니다. XML 기반 구성 메타데이터는 이 bean들을 상위 <beans/> 요소 내부의 <bean/> 요소로 구성합니다.

//예시
<beans>
  <bean>~~~~~~~</bean>
  <bean>~~~~~~~</bean>
</beans>

Java 기반 구성은 일반적으로 @Configuration 클래스 내에 @Bean annotation이 작성된 메소드를 사용합니다.

이러한 bean 정의는 어플리케이션을 구성하는 실제 객체에 해당합니다. 일반적으로 당신은 service-layer 객체, data Acess object(DAO), Struts Action 인스턴스와 같은 프레젠테이션 객체, Hibernate SessionFactories, JMS 대기열 등과 같은 인프라 객체를 정의합니다. 일반적으로 일부는 도메인 객체를 만들고 로드하는 것이 보통 DAO 및 비즈니스 로직이 맡은 일이기 때문에 컨테이너에 세분화(fine-grained)된 도메인 객체를 구성하지 않습니다. 그러나 Spring과 AspectJ의 통합을 사용하여 IoC 컨테이너의 제어 외부에서 생성된 객체를 구성할 수도 있습니다. 5.10.1 Spring으로 도메인 객체 종속성 주입을 위한 AspectJ 사용을 참조하십시오.

아래 코드는 XML 기반 구성 메타데이터의 기본 구조를 보여줍니다.

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="..." class="..."> ① ②
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->

</beans>

① id 속성은 각각의 bean 정의를 식별하는 문자열입니다.
② class 속성은 bean의 타입을 정의하고 완전히 풀어쓴 클래스 이름(패키지명 포함)(fully qualified classname)을 사용한다.

id 속성의 값은 협업 객체를 나타냅니다. 협업 객체를 나타내는 XML은 이 예시에서 표시되지 않습니다. 자세한 내용은 1.4 Dependencies를 참조하시길 바랍니다.

1.2.2 컨테이너 인스턴스화하기.

ApplicationContext 생성자에 제공된 위치 경로, 또는 경로들은 컨테이너가 로컬 파일 시스템, Java CLASSPATH 등과 같은 다양한 외부 리소스에서 구성 메타데이터를 로드할 수 있도록 하는 리소스 문자열입니다.

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

Note
Spring의 IoC 컨테이너에 대해 배운 후 URI 구문에 정의된 위치에서 InputStream을 읽기 위한 편리한 메커니즘을 제공하는 Spring의 리소스 추상화(2. Resource에 설명된 대로)에 대해 더 알고 싶을 수 있습니다. 특히 리소스 경로는 2.8 어플리케이션 컨텍스트 및 리소스 경로에 설명된 대로 어플리케이션 컨텍스트를 구성하는 데 사용됩니다.

다음 코드는 service-layer의 객체(services.xml) configuration 파일을 보여줍니다.

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- services -->

    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="itemDao" ref="itemDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for services go here -->

</beans>

다음 코드는 데이터 액세스 객체 daos.xml 파일을 보여줍니다.

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="accountDao"
        class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for data access objects go here -->

</beans>

앞의 예에서 service layer는 PetStoreServiceImpl 클래스와 JpaAccountDao 및 JpaItemDao 타입의 두 데이터 액세스 객체로 구성됩니다(JPA ORM 표준에 기반한).
속성의 이름 요소는 JavaBean 속성의 이름을 참조하고 ref 요소는 다른 빈 정의의 이름을 참조합니다. id와 ref 요소 사이의 이러한 연결은 협업하는(collaborating) 객체 간의 종속성(dependency)을 나타냅니다. 객체의 종속성을 구성하는 방법에 대한 자세한 내용은, 1.4 Dependency를 참조하세요.

XML 기반의 구성 메타데이터를 작성하는 법

bean 정의가 여러 XML 파일에 걸쳐 있는 것이 유용할 수 있습니다. 종종 각각의 개별 XML 구성 파일은 아키텍처의 논리적 계층 또는 모듈을 나타내기도 합니다.

어플리케이션 컨텍스트 생성자를 사용하여 이러한 모든 XML 조각들에서 bean 정의를 로드할 수 있습니다. 이 생성자는 이전 섹션에 표시된 것처럼, 여러 리소스 위치를 사용합니다.

여러 리소스 위치를 사용하는 예시)

new ClassPathXmlApplicationContext("services.xml", "daos.xml");

그 대신에, <import/> 요소를 하나 이상 사용하여 다른 파일에서 bean 정의를 로드합니다. 아래 코드에서는 그렇게 하는 방법을 보여줍니다.

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

앞의 예시를 봅시다.
외부 Bean 정의는 services.xml, messageSource.xml 및 themeSource.xml의 세 파일에서 로드되는 걸 확인할 수 있습니다.

모든 위치 경로는 import를 수행하는 정의 파일(definition file)에 상대적이므로 services.xml은 import를 수행하는 파일과 동일한 디렉토리 또는 클래스패스 위치에 있어야 하며(resource="service.xml"), messageSource.xml 및 themeSource.xml은 import하는 파일의 아래 위치인, 리소스 위치(reosurecs location) 속에 있어야 합니다.
=> 상대 경로로 불러오는 위 코드를 봤을 때, 디렉토리 구조가 아래 그림과 같아야 한다고 설명하는 부분이다.

보시다시피 맨 앞 /는 무시됩니다. 그러나 주어진 예시들은 상대경로이므로 맨 앞 슬래시를 사용하지 않는 것이 더 나은 형식입니다.
상위 요소를 포함하여 import는 파일의 내용은 Spring 스키마에 따라 유효한 XML 빈 정의여야 합니다.

Note
상대 경로 "../" 를 사용하여 부모 디렉토리의 파일을 참조하는 것은 가능하지만, 권장되지 않습니다. 이렇게 하면 현재 응용 프로그램 외부에 있는 파일에 대한 종속성이 생성됩니다. 특히, 이 참조는 런타임 해결 프로세스가 "가장 가까운" 클래스 경로 루트를 선택한 다음 상위 디렉토리를 조사하는 URL(예시: classpath: ../services.xml )과 같은 클래스패스에 대해 권장되지 않습니다. 클래스패스 구성 변경으로 인해 다른 잘못된 디렉토리가 선택될 수 있기 때문입니다.

상대 경로 대신 fully qualified된 리소스 위치를 사용할 수 있습니다.
(예: file:C:/config/services.xml or classpath:/config/services.xml)
그러나 어플리케이션의 configuration을 특정한 절대경로에 연결하고 있다는 점에 유의해야 합니다. 보통은, 런타임 시 JVM 시스템 속성에 대해 해결되는 "${...}" placeholder를 통해 절대경로 에 대한 간접 참조를 유지하는 것이 좋습니다.

네임스페이스(xmlns)는 import 지시문 기능을 제공합니다. 일반적인 bean 정의 이상의 추가 configuration 기능은 Spring 에서 제공하는 XML 네임스페이스 선택에서 사용할 수 있습니다.
ex): context와 util 네임스페이스

The Groovy Bean Definition DSL

외부화된 구성 메타데이터에 대한 추가적인 예시로, bean 정의는 Grails 프레임워크에서 알려진 것처럼 Spring의 Groovy Bean Definition DSL로 표현될 수도 있습니다. 일반적으로 이러한 configuration은 다음 예시에서 보여주는 구조처럼 ".groovy" 파일에 있습니다.

beans {
    dataSource(BasicDataSource) {
        driverClassName = "org.hsqldb.jdbcDriver"
        url = "jdbc:hsqldb:mem:grailsDB"
        username = "sa"
        password = ""
        settings = [mynew:"setting"]
    }
    sessionFactory(SessionFactory) {
        dataSource = dataSource
    }
    myService(MyService) {
        nestedBean = { AnotherBean bean ->
            dataSource = dataSource
        }
    }
}

이 configuration 스타일은 XML bean 정의와 거의 동일하며, Spring의 XML configuration namespace도 지원합니다. 또한 importBeans 지시문을 통해 XML bean 정의 파일을 import할 수 있습니다.

1.2.3 컨테이너 사용하기

ApplicationContext는 다양한 bean들과 그것들의 의존성의 레지스트리를 유지할 수 있는 고급 factory를 위한 인터페이스입니다.
T getBean(String name, Class <T> requiredType) 메소드를 사용하여 bean 인스턴스를 검색할 수 있습니다.

ApplicationContext를 통해 bean 정의를 읽고 그것들에게 접근(access)할 수 있습니다. 아래 예시 코드를 봅시다.

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

With Groovy configuration, bootstrapping looks very similar. 이는 Groovy를 인식하는 다양한 컨텍스트 구현 클래스를 가지고 있습니다. (뿐만 아니라 XML bean 정의도 이해합니다).

다음 예시는 Groovy configuration을 보여줍니다.

ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");

가장 유연한 변형은 Reader delegate와 결합된 `GenericApplicationContext`입니다.

예를 들어 아래 코드처럼 XML 파일용 XmlBeanDefinitionReader를 사용합니다.

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();

아니면, 아래 코드와 같이 Groovy 파일에 GroovyBeanDefinitionReader를 사용할 수도 있습니다.

GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();

다양한 configuration source로부터 bean 정의를 읽어오면서, 하나의 ApplicationContext에 위와 같은 reader delegate들을 연결하여 이용할 수 있습니다.

그런 다음 getBean을 이용하여 bean의 인스턴스를 검색할 수 있습니다. ApplicationContext 인터페이스에는 bean을 검색하기 위한 몇 가지 다른 메서드가 있지만 이상적으로는 어플리케이션 코드에 그 메소드들을 사용해서는 안 됩니다. 실제로, 어플리케이션 코드는 getBean() 메서드에 대한 호출이 아예 없어야 하기에, Spring API에 대한 종속성이 전혀 없습니다. 예를 들어, 웹 프레임워크와 Spring의 통합은 메타데이터(예: autowiring annotation)를 통해 특정 bean에 대한 종속성을 선언할 수 있도록 하면서, 컨트롤러, JSF-managed bean과 같은 다양한 웹 프레임워크 구성 요소에 대한 종속성 주입을 제공합니다.

!! Spring에서 bean을 직접 검색하는 메소드를 꺼리는 이유. 추후 공부가 필요한 문단

1.3 Bean 개요

Spring IoC 컨테이너는 1개 이상의 bean을 관리합니다. 이러한 bean들은 컨테이너에 제공한 구성 메타데이터를 이용하여 생성됩니다.
ex) XML 파일의 <bean/> 정의들.

컨테이너 내에, 이러한 bean 정의들은 아래 메타데이터를 포함하는 BeanDefinition 객체로 표시됩니다.

  • 패키지까지 포함된 클래스 이름(예: com.mycompany.notice.StockNotice): 일반적으로, 정의되는 bean의 실제 구현 클래스.

  • bean이 컨테이너 내에서 동작해야 하는 방식을 나타내는 bean 동작 구성 요소(범위, lifecycle callback 등등)

  • 해당 작업을 수행하는 bean을 위해 필요한 bean들에 대한 참조. =>이런 참조들을 collaborator, dependency 라고도 합니다.

  • 새로 생성된 객체에서 설정할 기타 구성 설정
    ex) pool의 크기 제한 또는 connection pool을 관리하는 bean에서 사용할 connection의 개수

이 메타데이터는 각각의 bean 정의를 구성하는 속성의 집합으로 변환됩니다.
아래 표에서 이러한 속성들에 대해 설명합니다.

The bean definition

PropertyExplained in...
ClassInstantiating Beans(Bean의 초기화)
NameNaming Beans
ScopeBean Scopes
Constructor argumentsDependency Injection
PropertiesDependency Injection
Autowiring modeAutowiring Collaborators
Lazy initialization modeLazy-initialized Beans
Initialization methodInitialization Callbacks
Destruction methodDestruction Callbacks

특정 bean을 생성하는 방법에 대한 정보를 포함하는 빈 정의 외에도, ApplicationContext 구현은 컨테이너 외부에서 (사용자에 의해) 생성된 기존 객체의 등록도 허용합니다. 이는 DefaultListableBeanFactory 구현을 반환하는 getBeanFactory() 메소드를 통해 ApplicationContext의 BeanFactory에 액세스함으로써 수행됩니다.
DefaultListableBeanFactoryregisterSingleton(..)registerBeanDefinition(..) 메소드를 통해 이 등록을 제공합니다. 그러나, 일반적인 어플리케이션은 오로지 regular한 bean 정의 메타데이터를 통해 정의된 bean들로만 작동합니다.

Note
Bean 메타데이터 및 수동으로 제공되는 싱글톤(singleton) 인스턴스는 컨테이너가 autowiring 및 기타 내부 검사 단계 동안 이들을 적절하게 추론하기 위해 가능한 한 빨리 등록되어야 합니다. 기존의 메타데이터 싱글톤 인스턴스를 오버라이딩하는 것은 어느 정도 지원되지만, 런타임 시 새 bean 등록(factory에 대한 실시간 접근과 동시에)은 공식적으로 지원되지 않으며 동시 액세스 예외(concurrent access exception)나 bean 컨테이너의 일관성 없는 상태, 또는 두 상황 모두로 이어질 수 있습니다.


1.3.1 bean 이름짓기

모든 bean는 하나 이상의 식별자를 가지고 있습니다. 이러한 식별자는 bean을 호스팅하는 컨테이너 내에서 고유해야 합니다. bean에는 일반적으로 하나의 식별자만 있습니다. 그러나, 2개 이상이 필요한 경우 추가 항목은 alias(가명)로 여겨질 수 있습니다.

XML 기반 구성 메타데이터에서는, id 속성, name 속성 또는 둘 다 사용하여 bean 식별자를 지정합니다. id 속성은 정확히 하나의 id를 지정합니다. 전통적으로 이러한 이름은 alphnumeric('myBean', 'someService' 등)이지만, 특수 문자도 포함할 수 있습니다. bean에 대한 다른 가명을 도입하려는 경우, 쉼표(,), 세미콜론(;) 또는 공백으로 구분하여 name 속성에 명시할 수도 있습니다. 역사적 참고로써, Spring 3.1 이전 버전에서 id 속성은 가능한 문자를 제한하는 xsd:ID 타입으로 정의되었습니다. 3.1부터 xsd:string 타입으로 정의됩니다. bean의 id 고유성은 더 이상 XML parser에 의함이 아님에도, 컨테이너에 의해 여전히 적용된다는 점에 유의하시기 바랍니다.

사용자는 bean의 name이나 id를 제공할 의무가 없습니다. 이름이나 ID를 명시적으로 제공하지 않으면, 컨테이너는 해당 빈에 대해 고유한 이름을 생성합니다. 그러나, 이름으로 해당 빈을 참조하고 싶으면, ref 요소 또는 Service Locator sytle lookup을 사용하여 이름을 제공해야 합니다. 이름을 제공하지 않는 동기는 1.4.2 중 소문단 inner beans, 1.4.5 autowiring collaborators과 관련이 있습니다.

Bean Naming Conventions

bean의 이름을 지정할 때 인스턴스 필드 이름에 대해 표준 Java 컨벤션을 사용하는 것이 bean Naming Conventions입니다. 즉, bean 이름은 소문자로 시작하고, 거기에서부터 Camel case입니다. (첫 문자만 소문자로 하고, 그 이후는 카멜 케이스 적용) ex) `accountManager`, `accountService`, `userDao`, `loginController`

bean의 이름을 일관되게 지으면 configuration을 더 쉽게 읽고 이해할 수 있습니다. 또한 Spring AOP를 사용한다면, 이름으로 관련된 bean들의 집합에 advice를 적용할 때 많은 도움이 됩니다.

Note
클래스패스에서 component scanning을 통해, Spring은 앞에서 설명한 규칙에 따라 이름 없는 컴포넌트에 대한 bean 이름을 생성합니다. 기본적으로 간단한 클래스 이름을 취하고 초기 문자를 소문자로 바꾸는 것입니다. 그러나, 두 개 이상의 문자가 있고 첫 번째와 두 번째 문자가 모두 대문자인 (비정상적) 특수한 경우에는 원래 대소문자가 유지됩니다. 이것들은 (여기서 Spring이 사용하는) java.beans.Introspector.decapitalize에 의해 정의된 것과 동일한 규칙입니다.

Aliasing a Bean outside the Bean Definition

bean 정의에서, bean에 대한 2개 이상의 이름을 제공할 수 있습니다, id 속성에 의해 지정된 최대 1개의 이름과 name 속성에 있는 다른 이름 여러가지를 이용해서. 이러한 이름은 동일한 빈에 대한 동등한 alias(별칭, 가명)이 될 수 있어서 어플리케이션의 각 component가 스스로 component 자체에 고유한 빈 이름을 사용하여 공통의 dependency(종속성)를 참조하도록 하는 것과 같은 일부 상황에 유용합니다.

그러나, bean이 실제로 정의된 곳에 모든 alias를 명시하는 것이 항상 적절한 것은 아닙니다. 때때로 다른 곳에서 정의된 bean에 대한 alias를 도입하는 것이 바람직합니다. 이는 보통 각각 자신만의 객체 정의 집합을 가지고 있는 하위 시스템으로 나뉘어진 대규모 시스템의 경우입니다. XML 기반 구성 메타데이터에서, 요소를 사용하여 이를 수행할 수 있습니다.
아래 코드에서 해당 방법을 보여줍니다.

<alias name="fromName" alias="toName"/>

위 코드의 경우, 이름이 fromName인 bean(동일한 컨테이너에 있는)은 이 alias 정의를 사용한 후, toName으로도 참조될 수 있습니다.

예를 들어, 하위시스템 A에 대한 구성 메타데이터는 subsystemA-dataSource라는 이름으로 DataSource를 참조할 수 있습니다. 하위시스템 B에 대한 구성 메타데이터는 subsystemB-dataSource라는 이름으로 DataSource를 참조할 수 있습니다. 이 두 하위 시스템을 모두 사용하는 메인 어플리케이션을 구성할 때, 메인 어플리케이션은 myApp-dataSource라는 이름으로 DataSource를 참조합니다. 세 이름이 모두 동일한 객체를 참조하도록 하기 위해, 구성 메타데이터에 아래와 같이 별칭 정의를 추가할 수 있습니다.

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

이제, 각 component와 메인 어플리케이션은 고유한 이름을 통해 dataSource를 참조할 수 있고 다른 정의와 충돌하지 않도록 보장되지만(효과적으로 네임스페이스 생성), 동일한 빈을 참조합니다.

Java-configuration
Java configuration을 사용하는 경우, @Bean annotation을 사용하여 alias를 제공할 수 있습니다. 자세한 내용은 1.12.3 @Bean annotation 사용하기를 참조하시기 바랍니다.

1.3.2. bean 인스턴스화하기

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

XML 기반 구성 메타데이터를 사용한다면, <bean/> 요소의 class 속성에 인스턴스화되는 객체의 타입(또는 클래스)을 명시합니다. 이 class 속성(내부적으로 BeanDefinition 인스턴스의 Class 속성임)은 보통 필수입니다. (예외의 경우, .1.3.2절 중 Instantiation by Using an Instance Factory Method1.7 Bean Definition Inheritance를 참조하시기 바랍니다.)
다음 두 가지 방법 중 하나로 Class 속성을 사용할 수 있습니다.

원문

  • Typically, to specify the bean class to be constructed in the case where the container itself directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java code with the new operator.

  • To specify the actual class containing the static factory method that is invoked to create the object, in the less common case where the container invokes a static factory method on a class to create the bean. The object type returned from the invocation of the static factory method may be the same class or another class entirely.
  • 생성되는 bean 클래스를 명시하는 방식.
    컨테이너 자체가 bean 생성자를 반사적으로 호출함으로써 bean을 직접 생성하는 경우입니다. new 연산자를 이용하는 Java 코드와 다소 동일합니다.

  • 객체를 생성하기 위해 호출되는 static factory 메소드를 포함하고 있는 실제 클래스를 명시하는 방식.
    컨테이너가 클래스 내의 static factory 메소드를 호출하여 bean을 생성하는, 덜 일반적인 경우입니다. static factory 메소드 호출에서 리턴된 객체 타입은 완전히 동일한 클래스일 수도, 완전히 다른 클래스일 수도 있습니다.

Nested class names

중첩 클래스(nested class)에 대한 bean 정의를 구성하고 싶다면, 중첩 클래스의 바이너리 이름이나 소스 이름을 사용할 수 있습니다.

예를 들어, `com.example` 패키지에 `SomeThing`이라는 클래스가 있고, 이 `SomeThing` 클래스에 `OtherThing`이라는 `static` 중첩 클래스가 있는 경우, 달러 기호(`$`) 또는 점(`.`)으로 구분할 수 있습니다. 따라서 bean 정의에서 `class`속성의 값은 `com.example.SomeThing$OtherThing` 또는 `com.example.SomeThing.OtherThing`이 됩니다.

생성자를 사용한 인스턴스화

생성자 접근 방식으로 bean을 생성할 때, 모든 일반 클래스들은 Spring에서 사용 가능하며 호환도 가능합니다. 즉, 개발되는 클래스는 특정 인터페이스를 구현하거나 특정한 방식으로 코딩될 필요가 없습니다. 간단히 bean 클래스를 명시하는 것만으로 충분합니다. 그러나, 특정 bean에 사용하는 IoC 타입에 따라, 기본(비어있는) 생성자가 필요할 수도 있습니다.

Spring IoC 컨테이너는 관리하고자 하는 모든 클래스를 사실상 거의 다 관리할 수 있습니다. managing true JavaBeans(실제 JavaBeans 관리?)에만 제한되지 않습니다. 대부분의 Spring 사용자는 기본(no-argument) 생성자와 컨테이너의 속성을 따라 모델링된 적절한 setter 및 getter만 있는 실제 JavaBeans를 선호합니다. 또한 컨테이너에 더 이국적인 non-bean-style의 클래스를 가질 수 있습니다. 예를 들어, JavaBean 사양을 절대적으로 준수하지 않는 레거시한 connection pool을 사용해야 한다면, 또한 Spring에서 이를 관리할 수 있습니다.

XML 기반 구성 메타데이터를 사용하여 아래와 같이 bean 클래스를 명시할 수 있습니다.

<bean id="exampleBean" class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

생성자에 인수를 제공하는 것과, 객체가 생성된 후 객체 인스턴스 속성을 설정하는 메커니즘에 대한 자세한 내용은 1.4.1 Injecting Dependencies를 참조하시길 바랍니다.

Instantiation with a Static Factory Method

static factory 메소드로 생성한 bean을 정의할 때, class 속성을 사용하여 static factory 메소드를 포함하는 클래스를, factory-method 라고 하는 속성을 이용하여 factory 메소드 자체의 이름을 명시해야 합니다. 이 메소드(with optional arguments, as described later)(=>후에 설명하는 추가적인 인수를 사용하여?)를 호출하여, 나중에는 생성자를 통해 만들어진 것처럼 처리되는 live한 객체를 리턴할 수 있어야 합니다.
이러한 bean 정의의 한 용도는 레거시 코드에서 static 팩토리들을 호출하는 것입니다.

아래 bean 정의 예시는 factory 메서드를 호출하여 bean이 생성되도록 명시합니다. 정의는 리턴되는 객체의 타입(클래스)을 지정하지 않고, 오히려 factory 메소드를 포함하는 클래스를 명시합니다. 이 예시에서, createInstance() 메소드는 static 메소드드여야 합니다. 아래 예시는 factory 메소드를 명시하는 방법을 보여줍니다.

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>

아래 코드는 위의 bean 정의와 함께 작동하는 클래스를 보여줍니다.

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

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

factory 메서드에 인수(선택 사항)를 제공하는 것과 객체가 factory에서 반환된 후 객체 인스턴스 속성을 설정하는 메커니즘에 대한 자세한 내용은 1.4.2 Dependencies and Configuration in Detail를 참조하시기 바랍니다.

Instantiation by Using an Instance Factory Method

static factory method를 통한 인스턴스화와 유사하게 인스턴스 factory 메소드를 사용한 인스턴스화는 컨테이너에서 기존 bean의 non-static 메소드를 호출하여 새 bean을 생성합니다. 이 메커니즘을 사용하려면, class 속성을 비워두고, factory-bean 속성에 객체를 생성하기 위해 호출되어야 하는 인스턴스 메소드를 포함하는 현재(또는 부모나 조상)컨테이너 안의 bean 이름을 명시해야 합니다. 그리고, factory-method 속성으로 factory 메서드 이름을 설정해야 합니다.
아래 예시는 위처럼 bean을 설정하는 방법을 보여줍니다.

<!-- the factory bean, which contains a method called createInstance() -->
<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;
    }
}

아래 예시와 같이 하나의 factory 클래스는 둘 이상의 factory 메소드를 보유할 수도 있습니다.

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

이 접근 방식은 factory bean이 종속성 주입(DI)을 통해 관리되고 설정될 수 있다는 것을 보여줍니다. 1.4.2 Dependencies and Configuration in Detail를 참조하시기 바랍니다.

Note
Spring 문서에서, "factory bean"은 Spring 컨테이너에 설정되어 인스턴스 또는 static factory 메소드를 통해 객체를 생성하는 bean을 의미합니다. 대조적으로, FactoryBean(대문자에 주의)은 Spring 고유의 FactoryBean 구현 클래스를 참조합니다.

Determining a Bean’s Runtime Type

원문

The runtime type of a specific bean is non-trivial to determine. A specified class in the bean metadata definition is just an initial class reference, potentially combined with a declared factory method or being a FactoryBean class which may lead to a different runtime type of the bean, or not being set at all in case of an instance-level factory method (which is resolved via the specified factory-bean name instead). Additionally, AOP proxying may wrap a bean instance with an interface-based proxy with limited exposure of the target bean’s actual type (just its implemented interfaces).

The recommended way to find out about the actual runtime type of a particular bean is a BeanFactory.getType call for the specified bean name. This takes all of the above cases into account and returns the type of object that a BeanFactory.getBean call is going to return for the same bean name.

!!수정 요망
=>번역문이 많이 어색하고, 스스로도 해석하기 어려워 그대로 놔둡니다. 학습하면서 이해했을 시 한글로 수정하겠습니다.


각주

1. fine-grained란?

grain의 원래 의미는, 보리나 밀 같은 곡식을 낟알로 만드는 작업이나 표면을 우둘투둘하게 하는 일을 뜻한다.
이때, 아주 곱고 섬세하게 하느냐, 아니면 듬성듬성 크게 하느냐에 따라 Fine과 Coarse라는 형용사를 붙인다. 이 개념이 소프트웨어 공학에 도입되어 어떤 프로세스를 잘게 쪼개느냐 아니면 굵게 쪼개서 뭉뚱그려 놓느냐를 표현할 때 쓰게 되었다.

출처: 코스 그레인드 (coarse-grained)와 파인 그레인드 (fine-grained)

되돌아가기

2. What is fully qualified classname?

The fully qualified name of a class is the name of the class prefixed with the package name. For example if class Address is in a package com.mycompany.myproject, then the fully qualified name of class Address is "com.mycompany.myproject.Address".
번역=> fully qualified classname은, 해당 클래스가 속한 패키지명까지 붙여 쓴 클래스의 이름이다.
예시로, Address 라는 클래스가 com.mycompany.myproject 패키지에 속해있다고 가정하자.
이때의 Address 클래스의 fully qualified name은 com.mycompany.myproject.Address이다.

출처: 스택오버플로우 질문 중 하나의 대답 참조.

되돌아가기


P.S. 동시에 영어 공부하기!
-cover: ~를 다루다
-assemble: 조립하다
-otherwise: 그렇지 않으면, 그 외에는
-be responsible for: ~를 맡다, ~를 책임지다
-intuitive: 직관적인, 이해하기 쉬운
-decouple: (연관관계에 있는 둘을) 분리시키다
-correspond: 일치하다, ~에 해당하다
-and so forth: ..등등
-and so on: ..등등
-delegate: 위임하다, 대표
-state: (동사) 명시하다
-destruction: 파괴, 소멸
-solely: 오로지, 단지
-in order for A to B: A가 B하기 위해 ~~
-concurrently: 동시에
-lead to 명사: ~로 이어지다
-alias: 별칭, 가명
-adequate: 적절한, 충분한
-desirable: 바람직한, 가치 있는
-accomplish: 수행하다, 완수하다, 성취하다 (=achieve)
-mandatory: 필수적인, 의무적인
-somewhat: 다소, 약간, 어느 정도
-invoke: (법, 규칙을) 적용하다, (프로그램 등을) 불러오다, 호출하다
-compatible: 호환이 되는, 양립될 수 있는
-virtually: 사실상, 거의, 가상으로
-adhere: 들러붙다, 부착되다, ~을 준수하다(명사: adherent)
-corresponding: ~에 해당하는, ~에 상응하는

profile
Oasis of Knowledge

0개의 댓글