Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

Develog

코드스테이츠 36일차 본문

코드스테이츠

코드스테이츠 36일차

안형준 2022. 6. 16. 18:44

학습 목표

  • Spring 컨테이너(Container)와 빈(Bean)의 의미를 이해할 수 있다.
  • 빈 스코프(Bean Scope)의 의미를 이해할 수 있다.
  • Java 기반 컨테이너(Container) 설정에 대해 이해할 수 있다.
  • Spring DI(Dependency Injection)의 의미를 이해할 수 있다.
  • Component 스캔에 대해 이해할 수 있다.

 

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

스프링 컨테이너(Spring Container)

스프링 컨테이너는 스프링 프레임워크의 핵심 컴포넌트이다.

스프링 컨테이너는 내부에 존재하는 애플리케이션 빈(Bean은 생성, 관리, 제거 등의 역할을 담당)의 생명주기를 관리한다.

Spring에 의하여 생성되고 관리되는 자바 객체를 Bean 이라고한다.

Spring 컨테이너(Container)의 특징

  • 스프링 컨테이너는 XML, 애너테이션 기반의 자바 설정 클래스로 만들 수 있다.
  • 예전에는 개발자가 xml을 통해 모두 설정해줬지만, 이러한 복잡한 부분들을 Spring Boot를 사용하면서 거의 사용하지 않게 되었다.
  • 빈의 인스턴스화, 구성, 전체 생명 주기 및 제거까지 처리한다.
  • 스프링 컨테이너를 통해 원하는 만큼 많은 객체를 가질 수 있다.
  • 의존성 주입을 통해 애플리케이션의 컴포넌트를 관리한다.

 

스프링 컨테이너는 왜 사용할까?

객체를 사용하기 위해서 new 생성자를 써야했는데 애플리케이션에서 이러한 객체가 무수히 많이 존재하고 서로 참조하게 되어있었기에 객체 간의 의존성을 낮추기 위해 Spring 컨테이너가 사용된다.

  • 서로 참조가 심할수록 의존성이 높다고 표현한다.
  • 낮은 결합도와 높은 캡슐화가 객체지향프로그래밍의 핵심 중 하나인데 높은 의존성은 이를 지키지 못하는 방법이 될 수 밖에 없다.

 

Spring 컨테이너가 해결법이 되는 이유

  • 기존의 방식으론 새로운 정책이 생기게 될 경우 변경 사항들을 수작업으로 수정이 필요했다.
  • 서로 의존이 많이 되어있지 않는 작업 초반 부에는 하나 하나 수정할 수 있겠지만, 점점 서비스의 코드가 거대 해질 경우 의존도는 높아져있을 것이고 그에 따른 코드의 변경도 많이 필요해질 것이다.
  • 하지만 스프링 컨테이너를 사용하면서 구현 클래스에 있는 의존을 제거하고 인터페이스에만 의존하도록 설계할 수 있다.

 

스프링 컨테이너의 생성 과정

  • 스프링 컨테이너는 Configuration Metadata를 사용한다.
  • 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록한다.
  • new AnnotationConfigApplicationContext(구성정보.class)로 스프링에 있는 @Bean의 메서드를 등록한다.
  • 애너테이션 기반의 자바 설정 클래스로 Spring을 만드는 것을 의미합니다.

 

Spring Container 생성

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  • 스프링 빈 조회에서 상속관계가 있을 시 부모타입으로 조회하면 자식 타입도 함께 조회한다.

 

XML 기반으로 만드는 ClassPathXmlApplicationContext도 있다.

  • <beans />에 필요한 값들을 설정한다.
  • <bean id=”...”> : 빈 정의를 식별하는데 사용되는 문자열이다.
  • <bean class=”...”> : Bean의 유형을 정의하고 클래스 이름을 사용한다.

 

스프링 컨테이너의 종류

BeanFactory

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

 

ApplicationContext

  • BeanFactory의 기능을 상속받아 제공한다.
  • 빈을 관리하고 검색하는 기능을 BeanFactory가 제공하고 그 외에 부가기능을 제공한다.
  • 부가 기능

 

new와 생성자 주입 코드 차이점

생성자 주입 코드의 장점

  • new를 사용하는 대신 생성자를 통해 의존 객체가 주입되고, 느슨한 의존 관계가 이루어진다.
  • Bean 설정에 따라서 유연하게 변하게 됩니다.
  • 생성자를 통해 어떤 구현 객체가 주입될지 알 수 없으며, 알 필요도 없다.
  • 어떤 객체가 주입될지는 외부 (AppConfig)에서 결정하게 된다.
  • 오로지 실행에만 집중하게 된다.

 

빈(Bean)

Spring 컨테이너가 관리하는 자바 객체를 의미하며, 하나 이상의 빈을 관리한다.

  • 빈(bean)은 인스턴스화된 객체를 의미한다.
  • 스프링 컨테이너에 등록된 객체를 스프링 빈이라고 한다.
  • @Bean이 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다.
  • 빈은 클래스의 등록정보, 게터/세터 메서드를 포함한다.
  • 빈은 컨테이너에 사용되는 설정 메타데이터로 생성된다.
  • 설정 메타데이터

 

ApplicationContext 사용하여 bean 정의를 읽고 액세스할 수 있다.

// create and configure beans

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



// retrieve configured instance

PetStoreService service = context.getBean("cmarket", cmarketService.class);



// use configured instance

List<String> userList = service.getUsernameList();

getBean 을 사용하여 bean의 인스턴스를 가져올 수 있다.

그 외에도 bean을 가져오는 방법은 여러가지가 있다.

하지만 실제적으로 응용 프로그램 코드에서는 getBean() 메서드로 호출하여 사용하면 안된다.

 

BeanDefinition

스프링은 다양한 설정 형식을 BeanDefinition이라는 추상화 덕분에 지원할 수 있는 것이다.

  • BeanDefinition (빈 설정 메타정보)

 

BeanDefintion 개체가 포함하고 있는 메타데이터

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

 

정리하자면

  • 스프링은 스프링 컨테이너를 통해 객체를 관리한다.
  • 스프링 컨테이너에서 관리되는 객체를 빈(Bean)이라고 한다.
  • @Configuration : 구성정보를 담당하는것을 설정할때 @Configuration 을 붙여준다.
  • @Bean : 각 메서드에 @Bean을 붙이면 스프링 컨테이너에 자동으로 등록이 된다.

 

빈 스코프(Bean Scope)

  • 특정 bean 정의에서 생성된 개체에 연결할 다양한 의존성 및 구성 값뿐만 아니라 특정 bean 정의에서 생성된 개체의 범위도 제어할 수 있다.
  • Spring Framework는 6개의 범위를 지원하며, 그 중 4개는 ApplicationContext를 사용하는 경우에만 사용할 수 있다.
  • bean은 여러 범위 중 하나에 배치 되도록 정의할 수 있다.
  • 구성을 통해 생성하는 개체의 범위를 선택할 수 있기 때문에 강력하고 유연하다.
  • 사용자 정의 범위를 생성할 수도 있다.

 

Scope Description
singleton (Default) Spring 컨테이너에 대한 단일 객체 인스턴스에 대한 단일 bean definition 범위를 지정한다.
prototype 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는 매우 짧은 범위의 스코프이다.
request 요청이 들어오고 나갈때 까지 유지되는 스코프이다.
session 세션이 생성되고 종료될 까지 유지되는 스코프이다.
application 웹의 서블릿 컨텍스와 같은 범위로 유지되는 스코프이다.
websocket 단일 bean definition 범위를 WebSocket 라이프사이클까지 확장한다. Spring ApplicationContext 컨텍스트에서만 유효합니다.

 

수 많은 객체를 생성하게 되면 위에 방식은 메모리 낭비와 효율성이 떨어지게 되는데, 이 문제를 해결하기 위해 싱글톤 패턴을 사용할 수 있다.

 

싱글톤(singleton) 스코프

클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴

  • 스프링 컨테이너의 시작과 함께 생성되어서 스프링 컨테이너가 종료될 때 까지 유지된다.
  • 싱글톤 빈의 하나의 공유 인스턴스만 관리하게 된다.
  • 해당 bean definition와 일치하는 ID 또는 ID를 가진 빈에 대한 모든 요청은 스프링 컨테이너에서 해당 특정 빈 인스턴스를 반환한다.
  • 스프링 컨테이너 종료시 소멸 메서드도 자동으로 실행된다.

 

즉 정리를 해보자면

  • 싱글톤은 해당 빈의 인스턴스를 오직 하나만 생성해서 사용하는 것을 의미한다.
  • 단일 인스턴스는 싱글톤 빈의 캐시에 저장된다.
  • 이름이 정해진 빈에 대한 모든 요청과 참조는 캐시된 개체를 반환한다.

 

쉽게 말해 싱글톤은 static과 같이 공통적인 부분을 담당한다 라고 생각하자

 

싱글톤 패턴 적용과정

  • static 영역에 객체 인스턴스를 미리 1개 생성한다.
  • 객체 인스턴스가 필요한 경우 getInstance() 메서드를 통해서만 조회할 수 있도록 한다.
  • 외부에서 생성자를 new로 새로 생성되는 것을 방지하기 위해 private 생성자로 생성한다.

 

DI 컨테이너만 사용했을 때의 결과값과 반대로 모든 객체는 같은 인스턴스를 바라보게 된다.

물론 스프링 컨테이너의 기본값은 싱글톤 이므로 직접 만들지 않아도 된다.

 

싱글톤 패턴의 문제점

  • 싱글톤 패턴을 구현하는 코드 자체가 굉장히 많다.
  • 의존관계상 클라이언트가 구체 클래스에 의존한다.
  • 지정해서 가져오기 때문에 테스트하기 어렵다.
  • private 생성자를 사용하여 자식 클래스를 만들기 어렵기 때문에 유연성이 떨어진다.
  • 속성 공유
  • Application 초기 구동 시 인스턴스 생성

 

하지만! 이러한 싱글톤 패턴 문제를 싱글톤 컨테이너가 해결해준다.

  • 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다.
  • 싱글톤 객체로 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다.
  • 스프링 컨테이너의 위 기능 덕분에 싱글턴 패턴의 모든 단점을 해결하며 객체를 싱글톤으로 유지할 수 있다.
  • AppConfig.java 파일을 수정한다.

 

싱글톤 방식의 주의점

  • 싱글톤 방식은 여러 클라이언트가 하나의 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 무상태(무상태(stateless)란 상태를 공유하는 필드 변수가 없는 것을 의미한다.)로 설계해야 한다.

 

총정리

bean 하나에 하나씩 메타 정보가 생성되고, 스프링 컨테이너는 이런 메타 정보를 기반으로 스프링 빈을 생성한다.

스프링 컨테이너에서 빈 스코프의 기본값은 싱글톤 스코프이다.

싱글톤 패턴을 사용할때 발생하는 문제점을 싱글톤 컨테이너로 해결할 수 있다.

 

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

@Bean and @Configuration

자바 기반 설정의 가장 중요한 애너테이션 2가지

  • @Configuration
  • @Bean
  • 메서드가 Spring 컨테이너에서 관리할 새 객체를 인스턴스화, 구성 및 초기화한다는 것을 나타내는 데 사용된다.

 

AnnotationConfigApplicationContext 를 사용하여 스프링 컨테이너를 인스턴스화 하는 방법

Spring 3.0에 도입된 애너테이션을 이용해 Config 클래스 설정하는 방법이다.

 

ApplicationContext 구현은 아래와 같은 애너테이션이 달린 클래스로 파라미터를 전달 받고 있다.

 

  • @Configuration 클래스가 입력으로 제공되면 @Configuration 클래스 자체가 Bean 정의로 등록되고 클래스 내에서 선언된 모든 @Bean 메서드도 Bean 정의로 등록된다.
  • @Component 클래스와 JSR-330 클래스가 제공되면 빈 정의로 등록 되며 필요한 경우 해당 클래스 내에서 @Autowired 또는 @Inject와 같은 DI 메타데이터가 사용되는 것으로 가정합니다.

 

@Autowired란 무엇인가?

@Autowired는 각 상황의 타입에 맞는 IoC컨테이너 안에 존재하는 Bean을 자동으로 주입해주게 된다.

 

@Bean 애너테이션을 사용하기

@Bean 애너테이션은 @Configuration-annoted 또는 @Component-annoted 클래스에서 사용할 수 있다.

@Bean 애너테이션을 메서드에 추가해서 Bean으로 정의(선언)할 수 있다.

 

빈 선언

빈 정의가 있는 인터페이스를 구현하여 bean configuration을 설정할 수 있다.

 

빈 의존성

@Bean 애너테이션이 추가된(@Bean-annotated) 메서드는 빈을 구축하는데 필요한 의존성을 나타내는데 매개 변수를 사용할 수 있다.

 

@Configuration 애너테이션을 사용하기

  • @Configuration는 해당 객체가 bean definitions의 소스임을 나타내는 애너테이션이다.
  • @Configuration는 @Bean-annoted 메서드를 통해 bean을 선언한다.
  • @Configuration 클래스의 @Bean 메서드에 대한 호출을 사용하여 bean 사이의 의존성을 정의할 수도 있다.

 

Bean 사이에 의존성 주입

@Configuration

public class AppConfig {



    @Bean

    public BeanOne beanOne() {

        return new BeanOne(beanTwo());

    }



    @Bean

    public BeanTwo beanTwo() {

        return new BeanTwo();

    }

}

Spring에 인스턴스화된 빈은 기본적으로 싱글톤 범위를 갖게 된다.

하위 클래스의 하위 메서드는 상위 메서드를 호출하고 새 인스턴스를 만들기 전에 먼저 컨테이너에 캐시된(범위 지정) bean이 있는지 확인한다.

 

Java 코드에서 애너테이션을 사용해 Spring 컨테이너를 구성하는 방법

@Import 애너테이션

  • XML 파일 내에서 요소가 사용되는 것처럼 구성을 모듈화하는데 사용된다.
  • 다른 구성 클래스에서 @Bean definitions를 가져올 수 있습니다.

 

@Configuration 클래스를 사용할 때, 자바 컴파일러는 구성 모델에 제약을 두며, 다른 빈에 대한 참조는 유효한 자바 구문 이어야한다.

 

@Bean 메서드는 빈 의존성을 설명하는 임의 개수 파라미터를 가질 수 있다.

@Autowired 및 @Value 주입 및 다른 bean과 동일한 기능을 사용할 수 있다.

@Configuration의 생성자 주입은 스프링 프레임워크 4.3에서만 지원된다.

대상 빈이 하나의 생성자만 정의하는 경우 @Autowired 지정할 필요가 없다.

 

빈 객체에 이름은 메서드 이름을 사용한다.

  • 직접 부여도 가능하다.
  • ex) @Bean(name="UserRepository")
  • 이름의 경우엔 항상 다른 이름을 부여해야 한다.
  • 빈 객체가 생성되면 빈 의존관계를 설정한다.

'코드스테이츠' 카테고리의 다른 글

코드스테이츠 38일차  (0) 2022.06.20
코드스테이츠 37일차  (0) 2022.06.17
코드스테이츠 35일차  (0) 2022.06.15
학습 계획표  (2) 2022.06.15
코드스테이츠 34일차  (0) 2022.06.14