카테고리 없음

[Spring] 스프링 빈 직접 등록하여 사용하기 ( + 장점 )

보보트레인 2024. 1. 9. 16:38

이 글을 쓰는 이유

스프링으로 Restcontroller를 사용하게 되면 Dependency에 따라 자동으로 의존성을 부여한다.

그 뜻은 간단히 풀이하면 스프링 서버를 실행하면 하나의 큰 컨테이너가 실행되고,

그 컨테이너에 gradle파일의 명세대로 컨테이너에 스프링 빈을 등록한다.

 

<예시>

의존성 부여

스프링은 이처럼 자동으로 스프링 빈을 등록하여 사용할 수 있다.

 

현재 코드 상황

기본적으로 나는 도메인 기반 폴더구조를 지향한다.

추가적으로 spring코드의 가독성을 높히고 재사용성을 재고하기 위해 크게 3가지로 코드를 분리한다.

1. controller > api 진입지점

2. 예외처리 > Service 폴더에 정리

3. SQL(DB) > Repository 폴더에 정리.

 

예시로 JdbcTemplate을 userRepository > userService > usercontroller 순서로 파라미터형식으로 주고받으며

mysql연동을 해야하는 경우가 있었다.

 

매번 JdbcTemplate를 생성자로 생성하고 이를 객체화 하여 각각의 함수마다 파라미터 형식으로 보내면 코드의 효율성이 떨어진다고 판단하여 아예 하나의 메서드를 만들어 공유하도록 의도했다.

 

다음의 코드를 각각 과정에 추가한다. ( userRepository > userService > usercontroller 순 )

 

<UserRepository>  ( JdbcTemplate를 가져온다 > UserRepository에 담는다. ) 

public class UserRepository {

    private final JdbcTemplate jdbcTemplate;

    public UserRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

 

<UserService> ( UserRepository를 생성하는데 사용될 JdbcTemplate를 파라미터로 보낸다 )

public class UserService {

    //jdbc템플릿 한번 보내서 계속 재활용 해서 쓰기위해 만든 코드 -> jdbcTemplates를 계속 주고받으면 빡셈.
    private final UserRepository userRepository;

    public UserService(JdbcTemplate jdbcTemplate) {
        //주고 받아야할 jdbc를 미리 UserRepository에 보내서 관리 ( 한번만 주고받을 수 있도록 )
        userRepository = new UserRepository(jdbcTemplate);
    }

 

<UserController> ( UserService를 생성하는데 사용될 JdbcTemplate를 파라미터로 보낸다 ) 

@RestController
public class UserController {
    private final UserService userService;
    //1. jdbc 선언 (생략)
    //2. jdbc 연결
    public UserController(JdbcTemplate jdbcTemplate){
        //주고 받아야할 jdbc를 미리 UserService에 보내서 관리 ( 한번만 주고받을 수 있도록 )
        this.userService = new UserService(jdbcTemplate);
    }

 

이렇게 코드를 작성해 놓으면,

매번 각각의 함수끼리 jdbc템플릿을 파라미터로 주고받을 필요 없이, jdbcTemplate.~로 쉽게 끌어다 쓸 수 있다.

 

그런데?

@RestController를 사용하는 UserController는 UserRepository처럼 직접 JdbcTemplate를 인스턴스화 하지 않아도 사용할 수 있었다. ( 스프링 컨테이너에 dependency에 의해 JdbcTemplate 스프링 빈이 담겼고, 이를 사용하는 @RestController어노테이션 덕에 Usercontroller에서는 직접 JdbcTemplate를 인스턴스화 할 필요가 없었다.)

UserRepository의 JdbcTemplate인스턴스화 과정.

 

하지만 나는 UserRepository를 생성할 때도, JdbcTemplate를 인스턴스화 없이 사용하고 싶었고,

그렇기 때문에 UserRepository의 스프링 빈 등록이 필수적으로 수반됐다.

 

왜? UserRepository가 스프링 빈이여야 JdbcTemplate를 인스턴스 없이 가져올 수 있는가?

 

스프링 컨테이너는 스프링빈을 의존성에 의해 자동으로 주입해주는데, 

이 기능이 사용되려면 해당 클래스가 컨테이너에 소속된 친구여야 한다.

즉, 날것의 클래스가 아닌 스프링 빈이여야 한다.

 

실제로 JdbcTemplageCongifuration.class파일에 들어가보면 jdbc를 미리 쳐둔 코드가 @Bean으로 등록되어있음을 확인할 수 있다.


그럼 UserRepository를 스프링 빈으로 만들어 보자!

어노테이션 @Repository를 붙힘으로써 클래스를 스프링 빈으로 바꿔주었다.


UserRepository와 UserController의 중간다리 역할을 하는 Service역할인 UserService 역시 스프링 빈으로 등록해서 JdbcTemplate를 굳이 UserRepository로 보낼 필요가 없도록 하자.

 

서비스 영역이기 때문에 @Service 어노테이션을 붙혀주면 된다.

 

이렇게 되면 뭐가 좋냐?

UserService는 UserRepository에 JdbcTemplate를 보내는 중간다리 역할을 하지 않아도 되어서 좋고,

UserRepository는 인스턴스를 생성할 필요 없이 바로 JdbcTemplate를 받아 쓸 수 있어서 편리하다.

 

<최종 코드>

UserController도 더이상 JdbcTemplate를 UserService로 보내줄 필요가 없다.

따라서 JdbcTemplate를 보내던 코드가 userService를 보내는 코드로 변경된다.

@RestController
public class UserController {
    private final UserService userService;
    //1. jdbc 선언 (생략)
    //2. jdbc 연결
    public UserController(UserService userService){
        this.userService = userService;
    }

 

UserService 역시 마찬가지다. JdbcTemplate대신 UserRepository를 보내면 된다.

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

 

자연스럽게 import부분을 보면 JdbcTemplate를 사용하지 않게 된다.

 

이로써 일반적인 클래스를, 스프링 빈으로 등록하여 컨테이너에서 제공하는 의존성 주입의 수혜를 받도록 코드들을 개선해 보았다.

 


결론 : UserService와 UserRepository를 빈으로 등록해줌으로써, 그 스프링 빈을 '직접' 가져올 수 있게 되었다.

덕분에 Controller나 Service에서 필요치 않은 JdbcTemplate를 제거할 수 있었다.

반응형