๊ด€๋ฆฌ ๋ฉ”๋‰ด

<Hello Hosung๐Ÿ˜Ž/>

[SpringBoot] ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection) ๊ฐœ๋…๊ณผ ํ™œ์šฉ ๋ณธ๋ฌธ

๐Ÿ’ป Java/ใ…คJava(SpringBoot)

[SpringBoot] ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection) ๊ฐœ๋…๊ณผ ํ™œ์šฉ

์ขŒ์ถฉ์šฐ๋Œ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ผ๊ธฐ๐Ÿง 2024. 11. 8. 08:19

Spring Boot๋Š” ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection, DI)์„ ํ†ตํ•ด ๊ฐ์ฒด ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ๊ด€๊ณ„ ์„ค์ •์„ Spring ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋‹ด๋‹นํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ณ , ๊ฐ์ฒด๋“ค์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๋ธ”๋กœ๊ทธ์—์„œ๋Š” Spring Boot์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๊ฐœ๋…๊ณผ ์‹ค์ œ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


1. ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection)๋ž€?


**์˜์กด์„ฑ ์ฃผ์ž…(DI)**์€ ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ , ์™ธ๋ถ€์—์„œ ์˜์กด ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…๋ฐ›๋„๋ก ํ•˜๋Š” ์„ค๊ณ„ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ๊ฐ์ฒด๊ฐ€ ์ž์‹ ์˜ ์˜์กด์„ฑ์„ ์ง์ ‘ ๊ด€๋ฆฌํ•˜๋Š” ๋Œ€์‹ , Spring๊ณผ ๊ฐ™์€ IoC(Inversion of Control) ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ  ์ฃผ์ž…ํ•ด์ค๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ณ , ๊ฐ ๊ฐ์ฒด๋“ค์ด ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž…์˜ ์žฅ์ 

์œ ์—ฐ์„ฑ: ์˜์กด ๊ด€๊ณ„๊ฐ€ ์„ค์ • ํŒŒ์ผ์ด๋‚˜ ์„ค์ • ํด๋ž˜์Šค์—์„œ๋งŒ ๊ฒฐ์ •๋˜๋ฏ€๋กœ ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ์ด ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ: ์‹ค์ œ ๊ฐ์ฒด ๋Œ€์‹  Mock ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•˜์—ฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“ˆํ™”: ๊ฐ ๋ชจ๋“ˆ์ด ๋…๋ฆฝ์ ์ด๊ฒŒ ๋˜์–ด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

Spring Boot์—์„œ๋Š” @Autowired, @Component, @Service ๋“ฑ์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ ์ฃผ์ž…์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. new ๋Œ€์‹  Spring์˜ ์˜์กด์„ฑ ์ฃผ์ž…


์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋Š” new ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ง์ ‘ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค

UserRepository userRepository = new UserRepository();
UserService userService = new UserService(userRepository);


์œ„์™€ ๊ฐ™์ด ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜๊ณ , ์˜์กด์„ฑ์„ ์ฝ”๋“œ์—์„œ ์ˆ˜๋™์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Spring์—์„œ๋Š” ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ†ตํ•ด Spring ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ฃผ์ž…ํ•ด์ฃผ๋ฏ€๋กœ, ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ์ฒด ์ƒ์„ฑ์— ๋Œ€ํ•œ ๊ด€๋ฆฌ์—์„œ ๋ฒ—์–ด๋‚˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Spring์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ™œ์šฉํ•˜๋ฉด, **new**๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ์‹ ๋Œ€์‹ , Spring ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์˜์กด์„ฑ ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์ฃผ์ž…ํ•ด์ค๋‹ˆ๋‹ค.

3. Spring์—์„œ ์˜์กด์„ฑ ์ฃผ์ž… ์‚ฌ์šฉํ•˜๊ธฐ

Spring Boot์—์„œ๋Š” @Autowired, @Component, **@Service**์™€ ๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ ์ฃผ์ž…์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3.1. ์˜ˆ์‹œ: UserService ํด๋ž˜์Šค์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepository;

    // ์ƒ์„ฑ์ž ์ฃผ์ž… (DI)
    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(User user) {
        userRepository.save(user);
    }
}

์œ„ ์ฝ”๋“œ์—์„œ UserService๋Š” UserRepository๋ฅผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค. Spring์€ UserRepository ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜์—ฌ **UserService**์— ์ฃผ์ž…ํ•ด ์ค๋‹ˆ๋‹ค. ์ด์ œ new UserRepository()๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์ฃ .

3.2. @Autowired๋กœ ์˜์กด์„ฑ ์ฃผ์ž…

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;  // Spring์ด ์ž๋™์œผ๋กœ ์ฃผ์ž…

    public void registerUser(User user) {
        userRepository.save(user);
    }
}

@Autowired ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด, Spring์ด UserRepository ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ ์ฐพ์•„์„œ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. ๋” ์ด์ƒ new๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์˜์กด์„ฑ์„ ์ฝ”๋“œ์—์„œ ์ง์ ‘ ์„ค์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

4. ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๋ฐฉ์‹

Spring Boot์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

ํ•„๋“œ ์ฃผ์ž…(Field Injection): @Autowired ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•„๋“œ์— ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•.
์ƒ์„ฑ์ž ์ฃผ์ž…(Constructor Injection): ์ƒ์„ฑ์ž์— ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•.
์„ธํ„ฐ ์ฃผ์ž…(Setter Injection): ์„ธํ„ฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•.

4.1. ํ•„๋“œ ์ฃผ์ž… (Field Injection)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // ์˜์กด์„ฑ ์ฃผ์ž… (Field Injection)
    @Autowired
    private UserRepository userRepository;

    public void saveUser(User user) {
        userRepository.save(user);
    }
}

ํ•„๋“œ ์ฃผ์ž…์€ ์ง๊ด€์ ์ด๊ณ  ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ต๊ณ  ์˜์กด์„ฑ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์•„ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4.2. ์ƒ์„ฑ์ž ์ฃผ์ž… (Constructor Injection)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepository;

    // ์ƒ์„ฑ์ž ์ฃผ์ž… (Constructor Injection)
    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void saveUser(User user) {
        userRepository.save(user);
    }
}

์ƒ์„ฑ์ž ์ฃผ์ž…์€ ์˜์กด์„ฑ ์ฃผ์ž…์„ ๋ถˆ๋ณ€ ๊ฐ์ฒด์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ์•ˆ์ „ํ•˜๊ณ , ํ…Œ์ŠคํŠธํ•  ๋•Œ Mock ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Spring 4.3 ์ด์ƒ์—์„œ๋Š” @Autowired ์–ด๋…ธํ…Œ์ด์…˜์„ ์ƒ์„ฑ์ž์— ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4.3. ์„ธํ„ฐ ์ฃผ์ž… (Setter Injection)

import org.springframework.stereotype.Service;

@Service
public class UserService {

    private UserRepository userRepository;

    // ์„ธํ„ฐ ์ฃผ์ž… (Setter Injection)
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void saveUser(User user) {
        userRepository.save(user);
    }
}

์„ธํ„ฐ ์ฃผ์ž…์€ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ ํ›„ ์˜์กด์„ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ, ์˜์กด์„ฑ ์„ค์ •์ด ๋ˆ„๋ฝ๋  ์œ„ํ—˜์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ์ž ์ฃผ์ž…๋ณด๋‹ค ์•ˆ์ „์„ฑ์€ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5. ์˜์กด์„ฑ ์ฃผ์ž… ํ™œ์šฉ ์˜ˆ์‹œ

์˜ˆ์‹œ 1: ์‚ฌ์šฉ์ž ์„œ๋น„์Šค ๊ตฌํ˜„
UserRepository ์ธํ„ฐํŽ˜์ด์Šค

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}


UserService ํด๋ž˜์Šค (์˜์กด์„ฑ ์ฃผ์ž…)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepository;

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

    public void registerUser(User user) {
        userRepository.save(user);
    }
}

UserController ํด๋ž˜์Šค (UserService ์ฃผ์ž…)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/register")
    public String registerUser(@RequestBody User user) {
        userService.registerUser(user);
        return "User registered successfully!";
    }
}


6. ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ™œ์šฉํ•œ ํ…Œ์ŠคํŠธ

Spring Boot์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ™œ์šฉํ•˜๋ฉด ํ…Œ์ŠคํŠธ๋ฅผ ๋”์šฑ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, UserService๋ฅผ ํ…Œ์ŠคํŠธํ•  ๋•Œ, UserRepository๋ฅผ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๊ฒฐํ•˜์ง€ ์•Š๊ณ  Mock ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์˜ˆ์‹œ

import static org.mockito.Mockito.*;

import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    public void testRegisterUser() {
        User user = new User("John Doe", "john@example.com");
        doNothing().when(userRepository).save(user);

        userService.registerUser(user);

        verify(userRepository, times(1)).save(user);
    }
}

์œ„์˜ ์˜ˆ์‹œ์ฒ˜๋Ÿผ, @Mock ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด UserRepository๋ฅผ Mock ๊ฐ์ฒด๋กœ ๋งŒ๋“ค๊ณ , @InjectMocks๋กœ UserService์— ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

7. ๋งˆ๋ฌด๋ฆฌ


Spring Boot์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์€ ๊ฐ์ฒด ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์„ค์ •ํ•˜๊ณ , ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์—ฌ์ค๋‹ˆ๋‹ค. ๋˜ํ•œ, ํ…Œ์ŠคํŠธ๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•˜์—ฌ ์ฝ”๋“œ์˜ ํ’ˆ์งˆ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ์˜์กด์„ฑ ์ฃผ์ž… ๋ฐฉ์‹์„ ์ž˜ ํ™œ์šฉํ•˜์—ฌ, ๋” ๋‚˜์€ Spring ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.