본문 바로가기
Java, Kotlin, Spring/Spring, Spring Boot

Spring IoC - 빈 등록 방법 5가지

by Wordbe 2021. 1. 10.
728x90

스프링

2003년 등장해서, java EE 와 호환관계이다. 서블릿 기반 애플리케이션을 만들 때 사용한다. 스프링 5부터는 WebFlux 지원으로 서블릿 기반 아닌 애플리케이션도 만들 수 있게 되었다.

 

 

디자인 철학

  • 모든 선택은 개발자의 몫이다.
  • 다양한 관점을 지향한다.
  • 하위 호환성을 지킨다.
  • API를 신중히 설계한다.
  • 높은 수준의 코드를 지향한다.

 

 

 


컨테이너와 빈

IoC(Inversion of Control, 제어의 역전)은 의존성주입 (Dependency Injection)이라고도 하며 의존성있는 객체를 직접 만드는 것이 아닌, 주입 받아 사용하는 방법이다.

BeanFactory 는 스프링 IoC 컨테이너의 가장 최상위 인터페이스이다.

빈이란?

빈(bean)은 스프링 IoC 컨테이너가 관리하는 객체이다.

빈 장점

1) 의존성 관리가 용이하다.

2) 빈으로 등록된 객체는 기본적으로 스코프가 '싱글톤'으로 정해진다.

  • 싱글톤 : 객체가 하나만 만들어짐. 재사용하여 메모리를 절약하며, 런타임시 성능 최적화에 유리하다. 특히 데이터베이스와 관련된 객체들은 필드가 많기 때문에 만드는 비용이 많이 들기 때문에 싱글톤이 효율적이다.
  • 프로토타입 : 매번 다른 객체가 만들어짐.

3) 라이프사이클 인터페이스를 지원해준다. 이를 활용할 수 있다.

ApplicationContext

  • BeanFactory 를 포함한 다른 컨테이너를 상속받음.

    메시지 소스 처리 기능도 있고, 이벤트 발행 기능, 리소스 로딩 기능 등이 있다.

  • 자주 사용하게 될 Beanfactory 이다.

 

 

 


다양한 빈 설정 방법

spring-boot-starter-web 의존성을 설정하면

관련 라이브러리들이 자동으로 다운받아진다.

  • spring-beans
  • spring-context
  • spring-core
  • spring-web
  • spring-webmvc 등등

예제를 만들어보자.

  • bookService 에 BookRepostory 객체를 주입시켜보자. bookService, bookRepostory 클래스는 같은 패키지에 있다.

bookService

public class BookService {

    BookRepository bookRepository;

    public void setBookRepository(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

bookRepository를 불러와서 세터 메소드를 이용해 값을 입력한다.

 

빈 설정 방법 1 - 원초적 방법

resources/application.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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bookService"
          class="me.wordbe.springgoahead.BookService">
        <property name="bookRepository" ref="bookRepository" />
    </bean>

    <bean id="bookRepository"
          class="me.wordbe.springgoahead.BookRepository" />


</beans>

xml 설정파일에 두 클래스를 각각 빈으로 등록하고, bookService의 특성(프로퍼티)으로 bookRepository를 등록하여 참조하게 하면 된다.

 

public class SpringApplication {

    public static void main(String[] args) {
        // bookService 와 bookRepository 가 IoC 컨테이너 (ApplicationContext) 에 빈으로 등록되었는지 확인한다.
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames)); // bookService, bookRepository

        // bookService 에 bookRepository가 주입되었는지 확인해본다.
        BookService bookService = (BookService) context.getBean("bookService");
        System.out.println(bookService.bookRepository != null); // true
    }

}

 

빈 설정 방법 2 - spring 2.5 버전

역시 xml 파일을 설정해준다. component-scan 기능이 추가되었다.

resources/application.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="me.wordbe.springgoahead" />


</beans>

패키지의 각각 클래스에 애노테이션을 붙여서 빈을 등록한다.

import org.springframework.stereotype.Repository;

@Repository
public class BookRepository {
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    @Autowired
    BookRepository bookRepository;

    public void setBookRepository(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

빈을 등록하려면 @Component 애노테이션을 클래스 위에 붙여주면 된다.

@Repository, @Service 어노테이션을 추적하면 결국 @Component 애노테이션을 따라간다. 명시적으로 저장소와 서비스를 나타내 주기에 용이하다.

여기에 의존성을 주입할 때 (DI) @Autowired 애노테이션을 활용한다.

이렇게 되면 xml 설정파일에 빈을 등록하는 것보다는 조금 더 손쉽게 애노테이션으로 빈을 등록할 수 있고, 자바 파일에서 바로 확인 가능하다.

 

빈 설정 방법 3 - Java Config

위 두 클래스와 같은 패키지에 설정파일(java)을 만든다. xml 보다 뭔가 더 친근하다.

ApplicationConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ApplicationConfig {

    @Bean
    public BookRepository bookRepository() {
        return new BookRepository();
    }

    @Bean
    public BookService bookService(BookRepository bookRepository) {
        BookService bookService = new BookService();

        // 의존성 주입 setter 이용
        bookService.setBookRepository(bookRepository);
        return bookService;
    }
}

설정 파일에서 빈 두개를 등록하고, 의존성 주입까지 했다.

이렇게 된 이상 나머지 두 클래스에서 애노테이션을 빼어도 빈 등록과 DI(의존성 주입)이 성공적으로 된 것이다.

메인 메소드를 살짝 수정한다.

public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
                // ...
    }

}

ApplicationContext (IoC 컨테이너)에 AnnotationConfigApplicationContext 를 통해 우리가 설정해 주었던 자바 설정 클래스를 등록해주어 빈팩토리를 받아온다.

( xml 설정에서는 ClassPathXmlApplicationContext 를 이용했었다. )

 

빈 설정 방법 4 - Java Config, ComponentScan

방법 3의 경우 기존 xml 에 bean 을 일일이 등록하던 것 처럼, java config 파일에도 똑같은 행위를 해야 했다. component scan으로 이 문제를 해결해보자.

ApplicationConfig.java

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackageClasses = SpringApplication.class) // 최상단 메인 클래스
public class ApplicationConfig {
}

컴포넌트스캔 애노테이션에 메인 클래스를 등록해줌으로써, 그 아래에 연관된 클래스에 등록된 모든 빈들을 알아서 스캔해주고 등록해주도록 한다.

물론, 각각 클래스 위에는 @Component 와 같은 애노테이션이 붙어야 하고, 의존성 주입을 위해 @Autowired 가 붙어야 한다.

 

빈 설정 방법 5 - springboot

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
        return args -> {
            String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
            Arrays.stream(beanDefinitionNames).forEach(
                    System.out::println
            );
        };
    }
}

@SpringBootApplication 어노테이션에는 @ComponentScan@Configuration이 내포되어 있다. 즉 자바 설정 파일자체가 이 어노테이션 하나로 완성된 것이다. 빈 등록, 의존성 주입을 알아서 해준다.

여기서 등록된 빈을 확인하기 위해 검색을 해보았는데 위와 같은 코드의 방법이 적절한 것 같다.

스프링 어플리케이션을 실행할 때 빈 등록이 된다. 그 때 커맨드라인에 등록된 빈이름들을 볼 수 있다. 내가 등록한 빈 말고도 수만은 빈들이 이미 등록된 것을 볼 수 있다.

 

 

 

 

728x90

'Java, Kotlin, Spring > Spring, Spring Boot' 카테고리의 다른 글

Spring IoC - ComponentScan, Bean scope  (2) 2021.01.10
Spring IoC - @Autowired  (4) 2021.01.10
Spring PSA 예시  (4) 2021.01.09
Spring AOP 예제  (2) 2021.01.08
Spring IoC란  (4) 2021.01.08

댓글