Bean 등록 및 의존 관계 설정방법

이용만·2023년 4월 4일
0

⭐️ 참고사이트 : https://katfun.tistory.com/178

Spring bean을 등록하는 방법은 크게 두 가지가 있습니다.

  • 어노테이션 이용
  • 직접 등록하기

대표적인 예시

@Configuration
public class SpringConfig {

    @Bean
    public PurchaseService purchaseService() {
        return new PurchaseService(purchaseRepository());
    }

    @Bean
    public PurchaseRepository purchaseRepository() {
        return new MemoryPurchaseRepository();
    }
}

@Configuration은 Bean을 수동으로 등록하는 것을 의미하는 어노테이션입니다.

내부에는 @Bean 어노테이션을 붙인 메소드마다, 각각 개별 Spring Bean을 등록하는 내용을 작성합니다.

PurchaseRepository는 의존하는 다른 bean이 없습니다.

따라서 별도의 인자 없이 생성해 주면 됩니다.

PurchaseService는 PurchaseRepository에 의존하는 bean입니다.

따라서 인자에 purchaseRepository()를 넣어 주면, Spring이 시작하면서 등록된 purchaseRepository를 purchaseService 생성 시에 넣어 줍니다 (@Autowired와 비슷).


Bean 직접 등록하기

자바 기반 설정의 가장 중요 애너테이션 2가지
@Bean, @Configuration

@Configuration
public class DependencyConfig {

    @Bean
    public MemberService memberService(){
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository(){
        return new MemberRepository();
    }

    @Bean
    public CoffeeService coffeeService(){
        return new CoffeeService(coffeeRepository());
    }

    @Bean
    public CoffeeRepository coffeeRepository(){
        return new CoffeeRepository();
    }
}

@Configuration

  • @Configuration은 @Bean에 추가 설정을 줘서 싱글톤으로 만들지 않는 이상 무조건 빈에 대해 싱글톤을 보장

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


-> 애너테이션을 이용해 Config 클래스 설정하는 방법입니다.

  • Spring 3.0에 도입된 AnnotationConfigApplicationContext 입니다.

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

    • @Configuration 클래스
    • @Component 클래스
  • @Configuration 클래스가 입력으로 제공되면 @Configuration 클래스 자체가 Bean 정의로 등록되고 클래스 내에서 선언된 모든 @Bean 메서드도 Bean 정의로 등록됩니다.

  • @Component 클래스가 제공되면 빈 정의로 등록되며 필요한 경우 해당 클래스 내에서 @Autowired 또는 @Inject와 같은 DI 메타데이터가 사용되는 것으로 가정합니다.

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(DependencyConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

@Configuration 클래스를 입력으로 사용 (DependencyConfig.class)

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에서 스프링 의존성 주입 애너테이션을 사용한 예제

@Bean

@Bean

  • 개발자가 컨트롤이 불가능한 외부 라이브러리들을 Bean으로 등록하고 싶은 경우
    에 사용된다.
  • 메소드 또는 어노테이션 단위에 붙일 수 있다.

지금까지는 스프링 빈을 등록할 때 자바 코드의 @Bean 설정 정보에 등록할 스프링 빈들을 직접 작성했습니다.
이렇게 수작업으로 등록하게 되면 설정 정보가 커지고, 누락하는 등 다양한 문제가 발생할 수 있습니다.


어노테이션 이용

Component Scan
스프링은 설정 정보 없이 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공합니다.

  • @ComponentScan은 @Component가 붙은 모든 클래스를 스프링 빈으로 등록해주기 때문에 설정 정보에 붙여주면 됩니다.
    • 의존관계도 자동으로 주입하는 @Autowired 기능도 제공합니다.
@Configuration
@ComponentScan
public class AutoDependencyConfig {
    
}
@Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Configuration.class))
public class DependencyConfig {

    @Bean
    public MemberService memberService(){
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository(){
        return new MemberRepository();
    }

    @Bean
    public CoffeeService coffeeService(){
        return new CoffeeService(coffeeRepository());
    }

    @Bean
    public CoffeeRepository coffeeRepository(){
        return new CoffeeRepository();
    }
}
  • 기존에 작성하던 DependencyConfig와의 비교한다면 @Bean으로 등록한 클래스를 볼 수 없습니다.
@Component
public class CoffeeService {
    private static CoffeeRepository coffeeRepository;

    @Autowired
    public CoffeeService(CoffeeRepository coffeeRepository){
        this.coffeeRepository = coffeeRepository;
    }

    public void createCoffee(Coffee coffee){
        coffeeRepository.postCoffee(coffee);
    }

    public Coffee editCoffee(Long coffeeId, String korName, int price){
        return coffeeRepository.patchCoffee(coffeeId, korName, price);
    }

    public Coffee getCoffee(Long coffeeId){
        return coffeeRepository.getCoffee(coffeeId);
    }

    public void deleteCoffee(Long coffeeId){
        coffeeRepository.deleteCoffee(coffeeId);
    }
}

코드들의 특징을 보면 기존에 코드에서 @Component와 @Autowired가 추가된 것을 볼 수 있습니다.
@ComponentScan - @ComponentScan이 등록된 곳에서 @Component를 가져오기 위해 사용됩니다.
@Autowired - 생성자 의존성 주입에 필요한 설정 정보 대신 의존관계 자동 주입을 해주게 됩니다.

컴포넌트 스캔 기본 대상

  • @Component : 컴포넌트 스캔에서 사용됩니다.

  • @Controller & @RestController : 스프링 MVC 및 REST 전용 컨트롤러에서 사용됩니다.

  • @Service : 스프링 비즈니스 로직에서 사용됩니다.

    • 특별한 처리를 하지 않는다.
    • 개발자들이 핵심 비즈니스 로직이 여기에 있다는비즈니스 계층을 인식하는데 도움이 된다.
  • @Repository : 스프링 데이터 접근 계층에서 사용됩니다.

    • 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환해준다.
  • @Configuration : 스프링 설정 정보에서 사용됩니다.

    • 스프링 설정 정보로 인식하고, 스프링 빈이 싱글톤을 유지하도록 추가 처리를 한다.

해당 클래스의 소스 코드에는 @Component를 포함하고 있습니다



필터

  • includeFilters : 컴포넌트 스캔 대상을 추가로 지정합니다.

  • excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정합니다.

  • FilterType 옵션

    • ANNOTATION: 기본값, 애너테이션으로 인식해서 동작합니다.
    • ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작합니다.
    • ASPECTJ: AspectJ 패턴을 사용합니다.
    • REGEX: 정규 표현식을 나타냅니다.
    • CUSTOM: TypeFilter라는 인터페이스를 구현해서 처리합니다.
profile
성장하는 개발자가 되고자 합니다.

0개의 댓글