1. 시작하게 된 계기 및 다짐 😮
  • 이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.

    • 그 날 배웠던 것을 길지 않아도 좋으니 정리하며 복습하는 습관 기르기
    • 주말에 다음주에 배울 내용들을 예습
    • 코딩 문제와 java코드들은 꾸준히 학습
    • 자료구조를 이용한 알고리즘 문제 해결 학습
  1. 학습 목표 😮
목표결과
Spring 컨테이너(Container)와 빈(Bean)의 의미를 이해O
빈 스코프(Bean Scope)의 의미를 이해O
Java 기반 컨테이너(Container) 설정에 대해 이해O
  1. 정리

Spring 컨테이너(Container) & 빈(Bean)

1. 스프링 컨테이너(Spring Container)
 - xml, 에너테이션,자바 코드 기반의 자바 설정 클래스로 구성
 - 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록한다.
 - 애플리케이션 빈의 생명주기를 관리 Bean의 생성,관리,제거등 역할 (빈의 인스턴스화, 구성, 전체 생명 주기 및 제거)
 - ApplicationContext라고도 불리며, 인터페이스로 구현되어 인터페이스에만 의존하도록(다형성 적용)
 - 원하는 만큼 많은 객체를 가질 수 있음
 - 의존성 주입을 통한 애플리케이션 컴포넌트 관리 , 스프링 컨테이너가 서로 다른 빈을 연결해 애플리케이션의 빈을 연결하는 역할을 함

2. 생성 과정[ # 사진]
 - Java(클래스) 기반의 애너테이션 기반설정이지만, 기존 XML 방식에 대한 이해도 필요
 - Configuration Metadata(구성 메타데이터)를 사용
 - 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록한다.
 - ApplicationContext 인터페이스의 구현체 
   1). AppConfig.class 등의 구성 정보를 지정해줘서 스프링 컨테이너를 생성해야 합니다.
   2). AppConfig에 있는 구성 정보를 통해서 스프링 컨테이너는 필요한 객체들을 생성하게 됩니다.
   3). 애플리케이션 클래스는 구성 메타데이터와 결합되어 ApplicationContext 생성 및 초기화된 후
       완전히 구성되고 실행 가능한 시스템 또는 애플리케이션을 갖게 됩니다.
 - new AnnotationConfigApplicationContext(구성정보.class)로 스프링에 있는 @Bean의 메서드를 등록
 - Bean 조회에서 상속관계가 있을 시, 부모타입으로 조회하면 자식 타입도 함께 조회함
    [ex] 모든 자바 객체의 최고 부모인 object타입으로 조회하면 모든 스프링 빈을 조회합니다.

 [예제 코드]
  - ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
 

3. 스프링 컨테이너의 종류
 1). BeanFactory
   - 최상위 인터페이스로, 빈을 등록하고 생성,조회, 관리하는 역할을 함
   - getBean() 메소드를 통해 빈을 인스턴스화 할 수 있음
   - @Bean이 붙은 메서드의 명을 스프링 빈의 이름으로 사용해 빈 등록을한다.

 2). ApplicationContext
   - BeanFactory의 기능을 상속받아 제공
   - BeanFactory기능 외의 부가기능들을 상속받아 제공
     (1) MessageSource : 메세지 다국화를 위한 인터페이스
     (2) EnviromentCapable : 개발, 운영 등 환경변수 등으로 나눠 처리하고, 
                                     애플리케이션 구동 시 필요한 정보들을 관리하기 위한 인터페이스
     (3) ApplicationEventPublisher : 벤트 관련 기능을 제공하는 인터페이스
     (4) ResourLoader : 파일, 클래스 패스, 외부 등 리소스를 편리하게 조회
     (5) BeanFactory

4. 컨테이너 인스턴스화
 - ApplicationContext 생성자에 제공된 위치 경로 또는 경로는 컨테이너가 로컬 파일 시스템, Java CLASSPATH 등과 같은    다양한 외부 리소스로부터 구성 메타데이터를 로드할 수 있도록 하는 리소스 문자열입니다.
 - 클라이언트는 구현객체가 뭔지 알필요가 없으며 외부(AppConfig)에서 결정함
 - 구현체 : AnnotationConfigApplicationContext
 
 [ex]    ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml"); 

[extra]
 - 모든 @Configuration 클래스는 CGLIB를 사용하여 하위 클래스로 분류됨
 - CGLIB는 코드 생성 라이브러리로서(Code Generator Library) 런타임에 동적으로 자바 클래스의 프록시를 생성해주는 기능을 제공
 - AppConfig클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록하는것빈(Bean)






빈(Bean)

★ 스프링 컨테이너에 의해 관리되는 재사용 소프트웨어 컴포넌트이다.

1. Bean
 - Spring 컨테이너가 관리하는 자바 객체들로, 인스턴스화된 객체를 의미
 - 설정 메타데이터(컨테이너 명령과 인스턴스화,설정,조립할 객체 정의)로 생성되며 등록정보, 게터/세터 메서드 포함
 - Spring 컨테이너에 등록된 객체를 스프링 빈이라함
 - @Bean이 적힌 메소드를 모두 호출하여 반환된 객체를 스프링 컨테이너에 등록

[extra]
Java Bean : 단순하게 클래스에서 필드와 Getter/Setter 메서드만 가지고있는 클래스

2. Bean 접근방법
 - getBean 을 사용하여 bean의 인스턴스를 가져올 수 있습니다.
 - 이 경우, Bean의 클래스를 알아야하여 IoC를 위반하며, 사용을 지양한다.

 [ex] PetStoreService service = context.getBean("cmarket", cmarketService.class);
       List<String> userList = service.getUsernameList();

3. BeanDefinition
 - 다양한 설정 형식을 BeanDefinition 이라는 추상화 덕분에 지원가능
 - BeanDefintion(빈 설정 메타정보)로 이를 활용하여 설정 메타데이터를 넣어서 Spring Bean 생성
 1). 속성에 따라 Bean 생성,관리 결정
 2). @Bean or <bean>당 1개의 메타 정보가 생성
 3). ★Spring이 설정 메타정보를 BeanDefinition 인터페이스를 통해 관리하기에 컨테이너 설정을 XML,Java로 할 수 있음

4. BeanDefinition 포함 메타데이터
- BeanClassName : 생성할 빈의 클래스 명(자바 설정처럼 팩토리 역할의 빈을 사용하면 없음)
- factoryBeanName : 팩토리 역할의 빈을 사용할 경우 이름, 예) appConfig
- factoryMethodName : 빈을 생성할 팩토리 메서드 지정, 예) memberService
- Scope : 싱글톤(기본값)
- lazyInit : 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라, 실제 빈을 사용할 때까지 최대한 생성을 지연처리 하는지 여부
- InitMethodName : 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명
- DestoryMethodName : 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드 명
- Constructor arguments, Properties : 의존관계 주입에서 사용한다. (자바 설정처럼 팩터리 역할의 빈을 사용하면 없음)
---

총 정리
 [★ 스프링 컨테이너(ApplicationContext)는 Beandefinition에 AppConfig.class(설정/메타 정보)를 기반으로 Beandefinition 구현체를 만들   어 이를 가지고 스프링 컨테이너가 Bean을 생성한다.]
 - 컨테이너는 먼저 객체를 생성하고 객체를 서로 연결합니다.
 - 객체를 설정하는 단계를 지나 마지막으로 생명주기 전반을 관리합니다.
 - 컨테이너는 객체의 의존성을 확인해 생성한 뒤 적절한 객체에 의존성을 주입합니다.
 - 스프링은 스프링 컨테이너를 통해 객체를 관리합니다.
 - 스프링 컨테이너에서 관리되는 객체를 빈(Bean)이라고 합니다.
    @Configuration : 구성정보를 담당하는것을 설정할때 @Configuration 을 붙여줍니다.
     [ex] import org.springframework.context.annotation.Configuration;
    @Bean : 각 메서드에 @Bean을 붙이면 스프링 컨테이너에 자동으로 등록이 됩니다.
     [ex] import org.springframework.context.annotation.Bean;

[extra]
공식문서 : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-basics
XML 설정 이해 : https://docs.oracle.com/cd/E13222_01/wls/docs81b/config_xml/overview.html

XML 파일 : WebLogic Server가 JMX API의 BEA 구현을 사용하여 실행하는 동안 만들고 수정하는 관리 대상 개체의 영구 저장소입니다. 
              config.xmlWebLogic Server가 다시 시작될 때 사용할 수 있도록 관리 개체에 대한 변경 사항을 저장하는 것입니다.






Bean Scope

1. Bean Scope
 - [bean definition에 의해 정의된 클래스의 실제 인스턴스를 만들기 위한 레시피
   빈이 스프링 컨테이너에서 (사용되는)존재할 수 있는 범위(시작-종료 범위)를 의미한다.]
 - 특정 bean 정의에서 생성된 개체에 연결할 다양한 의존성 및 구성 값뿐만 아니라  
   특정 bean 정의에서 생성된 개체의 범위도 제어할 수 있습니다.
 - Bean은 여러 범위 중 하나에 배치되도록 정의하며, 사용자 범위 생성도 가능하며, 구성을 통해 생성하는 개체의 범위를 선택할 수 있기 떄문에 강력하고 유연함

2. 싱글톤 스코프 (Singleton Scope)
 - 클래스의 인스턴스가 딱 1개만 생성 및 사용되는 것을 보장한 디자인 패턴
 - 컨테이너의 시작~종료까지 생성되어 유지
 - 싱글톤 빈의 하나의 공유 인스턴스만 관리
 - 해당 bean definition과 일치하는 ID를 가진 빈에 대한 모든 요청은 스프링 컨테이너에서 해당 특정 빈 인스턴스를 반환

3. 싱글톤 내용 정리
 - 단일 인스턴스는 싱글톤 빈의 캐시에 저장됨
 - 이름이 정해진 빈에 대한 모든 요청과 참조는 캐시된 개체를 반환한다.
     싱글톤 스코프의 스프링 빈은 여러번 호출해도 모두 같은 인스턴스 참조 주소값을 가진다.
 - 작동방식 [# 사진] 

4. 싱글톤 패턴의 문제점
 - 싱글톤 패턴 구현에 코드가 많음
 - 의존관계상 클라이언트가 구체 클래스에 의존한다.
 - 지정해서 가져오기에 테스트하기가 어렵다.
 - private 생성자를 사용하여 자식 클래스를 만들기 어려워 유연성이 떨어짐
 - 속성 공유 : 멀티 쓰레드 환경에서 한 쓰레드가 객체값을 바꾸면 다른 쓰레드의 객체(공유되서)값도 변경됨, 읽기만 권장됨
 - Application 초기 구동 시 인스턴스 생성
      - 애플리케이션 구동 시 생성(static)되므로 구동 시간이 증가함

5. 싱글톤 컨테이너가 이를 해결
 - 객체 인스턴스를 싱글톤으로 관리
 - 스프링 컨테이너가 싱글톤 컨테이너의 역할을 한다.
 - 싱글톤 객체를 생성/관리 하는 기능을 싱글톤 레지스트리라함
 - 이를 통해 모든 단점을 해결하며 객체를 싱글톤으로 유지 가능

6. 싱글톤 방식의 주의점
 - 여러 클라가 하나의 객체 인스턴스를 공유하기에 싱글톤 객체는 무상태로 설계해야됨
   1). 오직 객체는 읽기만 가능해야하며, 스프링 빈의 공유 값을 설정하면 장애가 발생할 수 밖에 없음

[Scope Description]
 1). singleton(default) : 스프링 컨테이너의 시작과 종료에 단일 객체(클래스 인스턴스)가 딱 하나만 생성되는 스코프(디자인 패턴) 
                              (각 Spring의 단일 객체 인스턴스에 대한 단일 bean definition)
 2). prototype : 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는 매우 짧은 범위의 스코프이다.
                     (컨터네이네게 빈을 요청할 때마다 매번 새로운 객체를 생성)
 3). request : 웹 요청이 들어오고 나갈때 까지 유지되는 스코프이다.
 4). session : 웹 세션이 생성되고 종료될 때 까지 유지되는 스코프이다.
 5). application : 웹의 서블릿 컨텍스와 같은 범위로 유지되는 스코프이다.
 6) websocket : 단일 bean definition 범위를 WebSocket의 라이프사이클까지 확장합니다. Spring ApplicationContext의 컨텍스트에서만 유효합니다.






Java 기반 컨테이너(Contianer) 설정

1. @Bean and @Configuration
 - 메서드가 Spring 컨테이너에서 관리할 새 객체를 인스턴스화, 구성 및 초기화 하는데 사용

 1). @Configuration : 컨텍스트를 인스턴스화 할 떄
 2). @Bean 

2. AnnotationConfigApplicationContext를 사용하여 스프링 컨테이너를 인스턴스화
 - ApplicationContext는 다음 애너테이션이 달린 클래스로 파라미터를 전달받음
  1). @Configuration 클래스
     - 입력으로 제공시, @Configuration 클래스 자체가 Bean 정의로 등록되고 클래스 내에서 선언된 모든 @Bean메서드도 Bean정의로 등록
  2). @Component 클래스
  3). @JSR-330 메타 데이터
     - 위 2개가 제공되면 빈 정의로 등록되며 필요한 경우 해당 클래스 내에서 @Autowired 또는 @Inject와 같은 DI메타데이터가 사용되는것으로 가정

★ Component vs Configuration 차이점
   1). Component : 메소드를 호출시 순수 메소드를 호출한 것처럼 스프링 컨텐스트에 등록되어 있는 빈이 반환되는 것이 아니라 새로운 빈이 반환
   2). Configuration : 메소드를 호출시 스프링 컨텍스트에 등록되어있는 빈을 반환한다.
   0). 아무것도 없을경우, 'lite' 모드로 처리됨

3. @AutoWired 
 - 자동으로 스프링 빈 객체를 특정 참조변수에 매핑해주는 것을 뜻함
 - DI에서 사용되는 어노테이션으로, 스프링 빈 인스턴스가 생성된 이후 @AutoWired를 설정한 메서드가 자동으로 호출되고 인스턴스가 자동으로 주입됨

[예제 Code]

(1) Configuration 클래스를 입력으로 사용시
  public static void main(String[] args) {
      ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
      MyService myService = ctx.getBean(MyService.class);
      myService.doStuff();
  }

(2) @Compoent or JSR-330이 생성자의 입력으로 사용
  public static void main(String[] args) {
      ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
      MyService myService = ctx.getBean(MyService.class);
      myService.doStuff();
}
# @Autowired - MyServiceImpl, Dependency1, Dependency2에서 스프링 의존성 주입 애너테이션을 사용한 예제입니다.


4. @Bean 에너테이션 사용
 - ex) @Bean(name="UserRepository")로 이름 직접 지정도 가능, 다른 이름이여야함
 - @Bean은 메서드-레벨 애너테이션이며, <bean/>에서 제공하는 일부 속성을 지원
   1). init-method
   2). destory-method
   3). autowiring
 - @Bean 애너테이션은 @Configuration-annoted 또는 @Compoent-annoted 클래스에서 사용가능
 - 빈 정의가 있는 인터페이스를 구현하여 bean configuration 설정 가능(Case 2)
[ex]

Case1).
 @Configuration
 public class AppConfig {

     @Bean
     public TransferServiceImpl transferService() {
         return new TransferServiceImpl();
     }
 }
---

Case2).
 public interface BaseConfig {

     @Bean
     default TransferServiceImpl transferService() {
         return new TransferServiceImpl();
     }
 }
 @Configuration
 public class AppConfig implements BaseConfig {

 }

# 심화참조 : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-java-bean-annotation


5. Configuration 애너태이션 사용
 - @Cinfiguration은 해당 객체가 bean definitions의 소스를 나타내는 애너태이션이다.
 - @Cinfiguration는 @Bean-annoted 메서드를 통해 bean을 선언
 - @Cinfiguration 클래스는 @Bean 메서드에 대한 호출을 사용하여 bean사이의 의존성을 정의 가능

 1). Bean 사이 의존성 주입
     - 빈이 서로 다른 의존성을 가질 때, 의존성을 표현하는 것은 다른 bean메서드를 호출하는 것처럼 간단
     - beanOne은 생성자 주입을 통해 beenTwo에 대한 참조를 받습니다.
     - 하위 클래스의 하위 메서드는 상위 메서드를 호출하고 새 인스턴스를 만들기 전에 먼저 컨테이너에 캐시된(범위 지정) bean이 있는지 확인합니다. ==> 기존에 만들어진 걸 반환해준다.


[ex]
@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        return new BeanOne(beanTwo());
    }

    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

6. Java 코드에서 애너테이션을 사용해 Spring 컨테이너를 구성하는 방법
 - Spring의 자바 기반 구성 기능 특징인 애너테이션을 사용해 복잡성을 줄일 수 있음
 - @Import 애너테이션
    1). XML파일 내에서 요소가 사용되는 것처럼 구성을 모듈화하는데 사용
    2). 다른 구성 클래스에서 @Bean definitions를 가져올 수 있음
 - 많은 @Configuration 클래스를 기억할 필요 없이 하나의 클래스만 처리 -> 컨테이너 인스턴스화 단순화

[예제 Code]

1). 다른 구성 클래스에서 @Bean definitions를 가져올 수 있습니다.
@Configuration
public class ConfigA {

    @Bean
    public A a() {
        return new A();
    }
}

@Configuration
@Import(ConfigA.class)
public class ConfigB {

    @Bean
    public B b() {
        return new B();
    }
}
---

2). 컨텍스트를 인스턴스화할 때 ConfigA.class와 ConfigB.class 모두 지정하는 대신 ConfigB만 제공하면 됩니다.

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);

    // now both beans A and B will be available...
    A a = ctx.getBean(A.class);
    B b = ctx.getBean(B.class);
}

2-1) 문제점
 - 실제로 사용될 때 빈은 1개의 구성 파일만 @Import 받지 않고 여러 구성 클래스 간에 걸쳐 서로 의존성을 갖습니다.
 - @Configuration 클래스를 사용할 때, 자바 컴파일러는 구성 모델에 제약을 두며, 다른 빈에 대한 참조는 유효한 자바 구문이어야 합니다.

2-2) 해결방법
 - @Bean 메서드는 빈 의존성을 설명하는 임의 개수 파라미터를 가질 수 있습니다.
 - @Autowired 및 @Value 주입 및 다른 bean과 동일한 기능을 사용할 수 있습니다.
 - 단, @Configuration의 생성자 주입은 스프링 프레임워크 4.3에서만 지원됩니다.
 - 대상 빈이 하나의 생성자만 정의하는 경우 @Autowired 지정할 필요가 없습니다.

[예제 Code]

@Configuration
public class ServiceConfig {

    @Autowired
    private AccountRepository accountRepository;

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl(accountRepository);
    }
}

@Configuration
public class RepositoryConfig {

    private final DataSource dataSource;

    public RepositoryConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public AccountRepository accountRepository() {
        return new JdbcAccountRepository(dataSource);
    }
}

@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {

    @Bean
    public DataSource dataSource() {
        // return new DataSource
    }
}

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
    // everything wires up across configuration classes...
    TransferService transferService = ctx.getBean(TransferService.class);
    transferService.transfer(100.00, "A123", "C456");
}


7. 의존관계 확인
 - 의존관계가 설정되는 조건
 - 내가 보고 있는 메서드가 어떤 메서드에 의존하고 있는지



[Extra]
★1. Full @Configuration vs “lite” @Bean mode
 - lite 모드에서는 @Configuration 어노테이션이 붙지 않은 클래스에서 @Bean어노테이션을 사용하는 것을 허용하지만
   이 경우 빈 간의 종속성 선언을 할 수 없음, 하나의 @Bean메소드가 @Bean메소드를 호출할 수 없음 => 계속 새 인스턴스를 생성하므로
2. Bean Definition Profiles : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-definition-profiles
3. PropertySource Abstraction : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-property-source-abstraction
4. Using @PropertySource : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-using-propertysource
5. Placeholder Resolution in Statements : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-placeholder-resolution-in-statements
6. @Bean 에너테이션 사용 : https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-java-bean-annotation






  1. 피드백 😮
  • Spring에서 빈을 생성하는 Container(메타 데이터 설정 정보 가지고 빈을 생성)와 이를 통해 만들어지는 Bean을 알아보았고, 이 Bean들이 어떠한 특성으로 생성되는지 알아보았다.

  • 기본적으로 Singlton패턴으로 생성되어 하나의 빈 객체가 존재하며, 생성된 빈 객체들간의 의존관계를 @Autowired를 이용하여 의존성을 연결해 준다.

  1. 앞으로 해야 될 것 😮
  • 매일 꾸준히 할 것
    • 꾸준히 velog 작성
    • Java 언어 및 Algorithm 공부(Coding-Test)
    • 틈틈히 운동 하기

  • 내일 해야 할 것
    • 의존성 주입 방법들 알아보기
    • ComponentScan 알아보기
profile
Will be great Backend-developer

0개의 댓글