2023년 1월 1일
08:00 AM
Buffering ...

최근 글 👑

[자바 스프링] 스프링 - 자동 의존성이란(DI)과 @Bean 개념 및 이해

2024. 1. 8. 00:13ㆍ[자바]스프링

 

 

 

1. 스프링 의존성이란?

 

이제 막 자바를 때고 스프링에 들어오면 스프링 DI의 개념이 많이 햇갈린다.

그리고 스프링 컨테이너에 왜 클래스를 등록하는지 개념이 확실히 잡히지 않을 것이다.

이번 포스트에서는 이 개념의 확실한 이해와 왜 스프링에 클래스를 등록하는지 완벽하게 이해하자.

 

 

1.의존성이란?

 

이 의존성을 알기위해선 자바 인터페이스와 상속의 개념을 확실히 알고 있어야한다.

여기에서는 인터페이스와 상속의 개념을 정확히 알고 있다는 가정하에 설명하겠다.

 

 

2.스프링에서 제공되는 클래스와 인터페이스

 

스프링에서는 개발자가 개발을 편리하게 할 수 있도록 인터페이스와 클래스를 제공한다.

하지만 내가 만약 어떠한 클래스를 재정의해서 사용하고싶다면 어떻게 해야할까?

이런 기능을 스프링에서는 유연하게 제공하는데

 

자 예시를 봐보자

public interface UserDetailsService {

   /**
    * Locates the user based on the username. In the actual implementation, the search
    * may possibly be case sensitive, or case insensitive depending on how the
    * implementation instance is configured. In this case, the <code>UserDetails</code>
    * object that comes back may have a username that is of a different case than what
    * was actually requested..
    * @param username the username identifying the user whose data is required.
    * @return a fully populated user record (never <code>null</code>)
    * @throws UsernameNotFoundException if the user could not be found or the user has no
    * GrantedAuthority
    */
   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

}

 

 

일단 이 인터페이스가 무엇을 하는지 알 필요는 없다.

 

이 인터페이스가 존재하고  자바 스프링에서는 이러한 인터페이스가 있다.

자바 스프링에서는 인터페이스가 있다면 기본 구현체가 대부분 함께 있다.

 

이 인터페이스는 자바 스프링에서 기본적인 구현체가

 

 

 

InMemoryUserDetailsManager라는 클래스가 인터페이스를 구현받고 있다.

 

자 잘보자

기본적으로 자바 스프링은
인터페이스가 있으면 스프링에서 정의된 클래스가 인터페이스를 구현받고 있는데

여기서 만약에 내가 UserDetailsService라는 인터페이스를 구현해서 스프링에 등록한다면

 

스프링은 이제부터 스프링이 기본적으로 제공하는 
구현체를 쓰는것이 아니라 우리가 만든 커스텀 클래스를 사용하게 된다.

 

@RequiredArgsConstructor
@Service
public class CustomUserDetailsService implements UserDetailsService {

    private final UserRepository repository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Account byUsername = repository.findByUsername(username);

        if(byUsername == null) throw new UsernameNotFoundException("인증 실패");


        AccountContext accountContext = new AccountContext(byUsername);

        return accountContext;
    }
}

 

 

자 잘보자 처음에 자바스프링이 UserDetailsService의 인터페이스를 구현한
클래스는 InMemoryDetailManager 클래스였다.

하지만 내가 이렇게 인터페이스를 구현해서
CustomUserDetailsSerivce@Bean이나 @Component로 

스프링 컨테이너에 등록하게 된다면
이제부터 스프링은  InMemoryDetailManager을 사용하는게 아니라

우리가 구현한 CustomUserDetailsSerivce이 클래스를 사용하게 된다.

 

이것이 의존성 주입이다.

 

스프링에서는 인터페이스가 있다면 기본적으로 구현한 클래스를 사용하다가,
해당 인터페이스를 구현해서
커스텀 클래스로 구현받아 스프링에 등록하면 

스프링은 더 이상 기본적인 클래스를 사용하는 것이
아닌 해당 인터페이스를 구현받은 클래스에 자동으로
의존성으로 주입시켜준다.

 

 

그렇다면 @Bean의 개념도 이해했으리라 믿는다.

 

이러한 구현체들을 @Bean으로 등록함으로써
자바 스프링에서 사용하는 기본적인 클래스를 사용하는 것이 아닌
해당 인터페이스의 구현체는 내가 만든 커스텀클래스로 쓰겠다는 의미이기도 하다.

 

그림으로 쉽게 본다면 이런느낌이다.

 

1. 개발자가 UserDetails를 구현안했을 때

 

빈 이름 (UserDetailsService)가 있고

이 구현체(빈 객체)는 InMemoryDetailsManager(스프링이 기본적으로 제공하는 클래스) 이다.

 

2. 개발자가 UserDetails를 구현하고 @Bean으로 등록했을 때

 

 

 

 

빈이름은 UserDetailsService가 되고 해당 구현체는 CustomUserDetailsSerivce가 된다.

 

이렇게 스프링은 스프링컨테이너를 통한 유연한 의존성 주입을 제공한다.

 

 

[인터페이스와 클래스의 자동 의존성]

 

 

예시 )

@RequiredArgsConstructor
@Service
public class CustomUserDetailsService implements UserDetailsService {

    private final UserRepository repository;

 

 

1. 인터페이스를 자동 의존성으로 주입할 때

 

대부분의 스프링 인터페이스는 기본 구현체가 함께 제공되기 때문에 별도의 구현 없이도

스프링 컨테이너가 의존성을 주입할 수 있다

 

인터페이스를 선언하고 자동으로 의존성 주입을 사용하더라도 스프링에서 함께 제공하는 기본 구현체가 있기 때문에 자동으로 등록이 된다.

 

2.클래스를 자동 의존성으로 주입할 때 

 

@Component
@Slf4j
public class UserCheckFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager manager;

 

 

AuthenticationManager은 스프링에서 제공하는 클래스이다.

 

클래스를 자동으로 주입할때는 반드시 이 클래스가 스프링 빈에 등록되어있어야 한다.

 

기본적으로 자바 스프링에서는 인터페이스의 경우 기본 구현체가 함께 제공되기에 자동으로 의존성이 추가되지만 클래스의 경우에는 스프링 컨테이너에 존재하지 않기 때문에 자동 의존성으로 추가해서 사용할려고 한다면

해당 클래스는 반드시 스프링 컨테이너에 있어야 한다.

 

요약

 

1. 인터페이스를 자동 의존성으로 사용하면 스프링의 기본클래스로 사용하게 됨.

(인터페이스를 선언하고  자동의존성만 추가하고 사용 가능 O)

 

2.클래스를 자동 의존성으로 사용할 수 없음 

(클래스를 자동의존성만 추가하고 사용 불가 (반드시 스프링 컨테이너에 등록필요))