๐ .NET Core์ ์์กด์ฑ ์ฃผ์ ์ปจํ ์ด๋ ํ์ฉ

์๋ ํ์ธ์, ์ํํธ์จ์ด ๊ฐ๋ฐ์ ์ฌ๋ฌ๋ถ! ์ค๋์ .NET Core์ ํต์ฌ ๊ธฐ๋ฅ ์ค ํ๋์ธ ์์กด์ฑ ์ฃผ์ (Dependency Injection, DI) ์ปจํ ์ด๋์ ๋ํด ๊น์ด ์๊ฒ ์์๋ณด๊ฒ ์ต๋๋ค. ์ด ๊ธ์ ํตํด ์ฌ๋ฌ๋ถ์ ์์กด์ฑ ์ฃผ์ ์ ๊ฐ๋ ๋ถํฐ ์ค์ ํ๋ก์ ํธ์์์ ํ์ฉ๊น์ง ์ ๋ฌธ์ ์ธ ์ง์์ ์์ ์ ์์ ๊ฒ์ ๋๋ค.
์์กด์ฑ ์ฃผ์ ์ ํ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์์ ํ์์ ์ธ ๋์์ธ ํจํด์ผ๋ก, ์ฝ๋์ ์ ์ง๋ณด์์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ ํฌ๊ฒ ํฅ์์ํต๋๋ค. .NET Core๋ ์ด๋ฌํ ์์กด์ฑ ์ฃผ์ ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํ๋ฉฐ, ๊ฐ๋ ฅํ DI ์ปจํ ์ด๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
ย
์ด ๊ธ์์๋ .NET Core์ DI ์ปจํ ์ด๋๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์ธํ ๋ค๋ฃฐ ์์ ์ ๋๋ค. ๊ธฐ๋ณธ ๊ฐ๋ ๋ถํฐ ์์ํด ๊ณ ๊ธ ๊ธฐ์ ๊น์ง, ์ค์ ํ๋ก์ ํธ์์ ๋ฐ๋ก ์ ์ฉํ ์ ์๋ ์ค์ฉ์ ์ธ ์ง์์ ์ ๊ณตํ๊ฒ ์ต๋๋ค. ํนํ, ์ต๊ทผ ํธ๋ ๋์ธ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์ ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์์ DI์ ์ค์์ฑ์ด ๋์ฑ ๋ถ๊ฐ๋๊ณ ์๋ ๋งํผ, ์ด์ ๋ํ ๋ด์ฉ๋ ํฌํจํ๊ฒ ์ต๋๋ค.
ย
์, ๊ทธ๋ผ .NET Core์ ์์กด์ฑ ์ฃผ์ ์ธ๊ณ๋ก ํจ๊ป ๋ ๋๋ณผ๊น์? ๐
๐ ๋ชฉ์ฐจ
- ์์กด์ฑ ์ฃผ์ ์ ๊ธฐ๋ณธ ๊ฐ๋
- .NET Core DI ์ปจํ ์ด๋ ์๊ฐ
- ์๋น์ค ์๋ช ๊ด๋ฆฌ
- ์์กด์ฑ ์ฃผ์ ๊ตฌํ ๋ฐฉ๋ฒ
- ๊ณ ๊ธ DI ํ ํฌ๋
- ์ฑ๋ฅ ์ต์ ํ์ ๋ชจ๋ฒ ์ฌ๋ก
- ์ค์ ํ๋ก์ ํธ์์์ DI ํ์ฉ
- ํ ์คํ ๊ณผ DI
- ๋ง์ดํฌ๋ก์๋น์ค์ DI
- ๊ฒฐ๋ก ๋ฐ ํฅํ ์ ๋ง
1. ์์กด์ฑ ์ฃผ์ ์ ๊ธฐ๋ณธ ๊ฐ๋ ๐งฉ
์์กด์ฑ ์ฃผ์ (Dependency Injection, DI)์ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์์ ์ค์ํ ๋์์ธ ํจํด ์ค ํ๋์ ๋๋ค. ์ด ๊ฐ๋ ์ ์ ๋๋ก ์ดํดํ๋ ๊ฒ์ .NET Core์ DI ์ปจํ ์ด๋๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
1.1 ์์กด์ฑ์ด๋?
์์กด์ฑ์ ํ ํด๋์ค๊ฐ ๋ค๋ฅธ ํด๋์ค์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ๋ ๋ฐ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, OrderService
ํด๋์ค๊ฐ PaymentProcessor
ํด๋์ค์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค๋ฉด, OrderService
๋ PaymentProcessor
์ ์์กดํ๋ค๊ณ ๋งํ ์ ์์ต๋๋ค.
ย
์ ํต์ ์ธ ๋ฐฉ์์์๋ ์์กด์ฑ์ ๋ค์๊ณผ ๊ฐ์ด ์ฒ๋ฆฌํ์ต๋๋ค:
public class OrderService
{
private PaymentProcessor _paymentProcessor;
public OrderService()
{
_paymentProcessor = new PaymentProcessor();
}
public void ProcessOrder(Order order)
{
// ์ฃผ๋ฌธ ์ฒ๋ฆฌ ๋ก์ง
_paymentProcessor.ProcessPayment(order.TotalAmount);
}
}
์ด ๋ฐฉ์์ ๋ฌธ์ ์ ์ OrderService
๊ฐ PaymentProcessor
์ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ์ ๊ฐํ๊ฒ ๊ฒฐํฉ๋๋ค๋ ๊ฒ์
๋๋ค. ์ด๋ ์ฝ๋์ ์ ์ฐ์ฑ์ ๋จ์ด๋จ๋ฆฌ๊ณ ํ
์คํธ๋ฅผ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค.
1.2 ์์กด์ฑ ์ฃผ์ ์ ์ ์
์์กด์ฑ ์ฃผ์ ์ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ๋๋ค. ํด๋์ค๊ฐ ์์ ์ ์์กด์ฑ์ ์ง์ ์์ฑํ๋ ๋์ , ์ธ๋ถ์์ ์์กด์ฑ์ ์ ๊ณต๋ฐ์ต๋๋ค. ์ด๋ฅผ ํตํด ๋์จํ ๊ฒฐํฉ(Loose Coupling)์ ๋ฌ์ฑํ ์ ์์ต๋๋ค.
ย
์์กด์ฑ ์ฃผ์ ์ ์ ์ฉํ ์์:
public interface IPaymentProcessor
{
void ProcessPayment(decimal amount);
}
public class OrderService
{
private readonly IPaymentProcessor _paymentProcessor;
public OrderService(IPaymentProcessor paymentProcessor)
{
_paymentProcessor = paymentProcessor;
}
public void ProcessOrder(Order order)
{
// ์ฃผ๋ฌธ ์ฒ๋ฆฌ ๋ก์ง
_paymentProcessor.ProcessPayment(order.TotalAmount);
}
}
์ด์ OrderService
๋ ๊ตฌ์ฒด์ ์ธ PaymentProcessor
๊ตฌํ์ ์์กดํ์ง ์๊ณ , ์ถ์ํ๋ IPaymentProcessor
์ธํฐํ์ด์ค์ ์์กดํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ค์ํ ๊ฒฐ์ ์ฒ๋ฆฌ ๋ฐฉ์์ ์ฝ๊ฒ ๊ต์ฒดํ ์ ์๊ฒ ๋์์ต๋๋ค.
1.3 ์์กด์ฑ ์ฃผ์ ์ ์ด์
- ์ ์ฐ์ฑ ํฅ์: ๊ตฌํ์ฒด๋ฅผ ์ฝ๊ฒ ๊ต์ฒดํ ์ ์์ด ์์คํ ์ ์ ์ฐ์ฑ์ด ์ฆ๊ฐํฉ๋๋ค.
- ํ ์คํธ ์ฉ์ด์ฑ: ๋ชฉ(Mock) ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ๋จ์ ํ ์คํธ๊ฐ ์ฌ์์ง๋๋ค.
- ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ: ๋์ผํ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ์ฌ๋ฌ ํด๋์ค๋ฅผ ์ฝ๊ฒ ๊ต์ฒดํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ: ๊ฐ์ฒด ์์ฑ๊ณผ ์ฌ์ฉ์ ๋ถ๋ฆฌํ์ฌ ๋จ์ผ ์ฑ ์ ์์น์ ์งํฌ ์ ์์ต๋๋ค.
- ์ ์ง๋ณด์์ฑ ํฅ์: ์ฝ๋ ๊ฐ์ ๊ฒฐํฉ๋๊ฐ ๋ฎ์์ ธ ์ ์ง๋ณด์๊ฐ ์ฌ์์ง๋๋ค.
1.4 ์์กด์ฑ ์ฃผ์ ์ ์ ํ
์์กด์ฑ ์ฃผ์ ์ ์ฃผ๋ก ์ธ ๊ฐ์ง ๋ฐฉ์์ผ๋ก ๊ตฌํ๋ฉ๋๋ค:
- ์์ฑ์ ์ฃผ์ (Constructor Injection): ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๋ฐฉ์์ผ๋ก, ํด๋์ค์ ์์ฑ์๋ฅผ ํตํด ์์กด์ฑ์ ์ฃผ์ ํฉ๋๋ค.
- ์์ฑ ์ฃผ์ (Property Injection): ๊ณต๊ฐ ์์ฑ์ ํตํด ์์กด์ฑ์ ์ค์ ํฉ๋๋ค.
- ๋ฉ์๋ ์ฃผ์ (Method Injection): ๋ฉ์๋ ๋งค๊ฐ๋ณ์๋ฅผ ํตํด ์์กด์ฑ์ ์ ๋ฌํฉ๋๋ค.
.NET Core์ DI ์ปจํ ์ด๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ฑ์ ์ฃผ์ ์ ์ง์ํ๋ฉฐ, ์ด๋ ๊ฐ์ฅ ๊ถ์ฅ๋๋ ๋ฐฉ์์ ๋๋ค.
1.5 IoC (Inversion of Control)
์์กด์ฑ ์ฃผ์ ์ IoC(์ ์ด์ ์ญ์ ) ์์น์ ํ ํํ์ ๋๋ค. IoC๋ ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์ ์ญ์ ์ํค๋ ์ํํธ์จ์ด ๋์์ธ ์์น์ ๋๋ค. ์ ํต์ ์ธ ํ๋ก๊ทธ๋๋ฐ์์๋ ํ๋ก๊ทธ๋๋จธ๊ฐ ํ๋ก๊ทธ๋จ์ ํ๋ฆ์ ์ ์ดํ์ง๋ง, IoC์์๋ ํ๋ ์์ํฌ๊ฐ ๊ทธ ์ญํ ์ ๋ด๋นํฉ๋๋ค.
ย
DI๋ IoC๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ก, ๊ฐ์ฒด์ ์์ฑ๊ณผ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ๋ฐ์๊ฐ ์๋ DI ์ปจํ ์ด๋๊ฐ ๊ด๋ฆฌํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ฐ๋ฐ์๋ ๋น์ฆ๋์ค ๋ก์ง์ ๋ ์ง์คํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ ๋ค์ด์ด๊ทธ๋จ์ IoC ์ปจํ ์ด๋๊ฐ ์ด๋ป๊ฒ ์๋น์ค๋ค์ ์์กด์ฑ์ ๊ด๋ฆฌํ๊ณ ์ฃผ์ ํ๋์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค. ์ปจํ ์ด๋๋ ๊ฐ ์๋น์ค์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๊ณ , ํ์ํ ๋ ์ ์ ํ ์์กด์ฑ์ ์ฃผ์ ํฉ๋๋ค.
1.6 SOLID ์์น๊ณผ ์์กด์ฑ ์ฃผ์
์์กด์ฑ ์ฃผ์ ์ SOLID ์์น, ํนํ ์์กด์ฑ ์ญ์ ์์น(Dependency Inversion Principle, DIP)๊ณผ ๋ฐ์ ํ ๊ด๋ จ์ด ์์ต๋๋ค. DIP๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์๋ฉ๋๋ค:
- ์์ ์์ค ๋ชจ๋์ ํ์ ์์ค ๋ชจ๋์ ์์กดํด์๋ ์ ๋ฉ๋๋ค. ๋ ๋ค ์ถ์ํ์ ์์กดํด์ผ ํฉ๋๋ค.
- ์ถ์ํ๋ ์ธ๋ถ ์ฌํญ์ ์์กดํด์๋ ์ ๋ฉ๋๋ค. ์ธ๋ถ ์ฌํญ์ด ์ถ์ํ์ ์์กดํด์ผ ํฉ๋๋ค.
์์กด์ฑ ์ฃผ์ ์ ์ด ์์น์ ์คํํ๋ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์ ๋๋ค. ์ธํฐํ์ด์ค๋ ์ถ์ ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ์์กด์ฑ์ ์ ์ํจ์ผ๋ก์จ, ๊ณ ์์ค ๋ชจ๋๊ณผ ์ ์์ค ๋ชจ๋ ์ฌ์ด์ ์ง์ ์ ์ธ ์์กด์ฑ์ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
1.7 ์์กด์ฑ ์ฃผ์ ์ ํ๊ณ์ ์ฃผ์์
์์กด์ฑ ์ฃผ์ ์ด ๋ง์ ์ด์ ์ ์ ๊ณตํ์ง๋ง, ๋ช ๊ฐ์ง ์ฃผ์ํด์ผ ํ ์ ๋ ์์ต๋๋ค:
- ๋ณต์ก์ฑ ์ฆ๊ฐ: ํฐ ํ๋ก์ ํธ์์๋ DI ์ค์ ์ด ๋ณต์กํด์ง ์ ์์ต๋๋ค.
- ๋ฐํ์ ์ค๋ฅ: ์ปดํ์ผ ์์ ์ด ์๋ ๋ฐํ์์ ์์กด์ฑ ๋ฌธ์ ๊ฐ ๋ฐ๊ฒฌ๋ ์ ์์ต๋๋ค.
- ๊ณผ๋ํ ์ถ์ํ: ๋ถํ์ํ ์ถ์ํ๋ก ์ธํด ์ฝ๋๊ฐ ๋ณต์กํด์ง ์ ์์ต๋๋ค.
- ์ฑ๋ฅ ์ํฅ: ์์กด์ฑ ํด๊ฒฐ ๊ณผ์ ์ด ์ฝ๊ฐ์ ์ฑ๋ฅ ์ค๋ฒํค๋๋ฅผ ๋ฐ์์ํฌ ์ ์์ต๋๋ค.
์ด๋ฌํ ํ๊ณ์ ๋ค์ ์ ์ ํ ์ค๊ณ์ .NET Core์ ๊ฐ๋ ฅํ DI ์ปจํ ์ด๋๋ฅผ ํ์ฉํจ์ผ๋ก์จ ๋๋ถ๋ถ ๊ทน๋ณตํ ์ ์์ต๋๋ค.
์ด์ ์์กด์ฑ ์ฃผ์ ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ์ ์ดํดํ์ จ์ ๊ฒ์ ๋๋ค. ๋ค์ ์น์ ์์๋ .NET Core์ DI ์ปจํ ์ด๋์ ๋ํด ์์ธํ ์์๋ณด๊ฒ ์ต๋๋ค. .NET Core๊ฐ ์ด๋ป๊ฒ ์ด๋ฌํ ๊ฐ๋ ๋ค์ ๊ตฌํํ๊ณ ์๋์ง, ๊ทธ๋ฆฌ๊ณ ๊ฐ๋ฐ์๋ค์ด ์ด๋ป๊ฒ ์ด๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ ์ ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
2. .NET Core DI ์ปจํ ์ด๋ ์๊ฐ ๐งฐ
.NET Core์ ์์กด์ฑ ์ฃผ์ (DI) ์ปจํ ์ด๋๋ ํ๋ ์์ํฌ์ ํต์ฌ ๊ตฌ์ฑ ์์ ์ค ํ๋์ ๋๋ค. ์ด ์ปจํ ์ด๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์กด์ฑ์ ๊ด๋ฆฌํ๊ณ , ํ์ํ ์์ ์ ์ ์ ํ ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ์ฃผ์ ํ๋ ์ญํ ์ ํฉ๋๋ค. .NET Core์ DI ์ปจํ ์ด๋๋ ๊ฐ๋ณ๊ณ ์ ์ฐํ๋ฉฐ, ํ์ฅ์ฑ์ด ๋ฐ์ด๋ ๋ค์ํ ์๋๋ฆฌ์ค์ ์ ์ฉํ ์ ์์ต๋๋ค.
2.1 .NET Core DI ์ปจํ ์ด๋์ ํน์ง
.NET Core์ DI ์ปจํ ์ด๋๋ ๋ค์๊ณผ ๊ฐ์ ์ฃผ์ ํน์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค:
- ๋ด์ฅํ: ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น ์์ด .NET Core์ ๊ธฐ๋ณธ์ผ๋ก ํฌํจ๋์ด ์์ต๋๋ค.
- ๊ฒฝ๋ํ: ์ต์ํ์ ์ค๋ฒํค๋๋ก ๋น ๋ฅธ ์ฑ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- ํ์ฅ์ฑ: ์ฌ์ฉ์ ์ ์ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ: ๊ฐ์ฒด์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ธ๋ฐํ๊ฒ ์ ์ดํ ์ ์์ต๋๋ค.
- ์ปจ๋ฒค์ ๊ธฐ๋ฐ: ๋ช ์์ ์ธ ๊ตฌ์ฑ ์์ด๋ ๋ง์ ๊ฒฝ์ฐ ์๋์ผ๋ก ์์กด์ฑ์ ํด๊ฒฐํฉ๋๋ค.
2.2 DI ์ปจํ ์ด๋ ์ค์
.NET Core ์ ํ๋ฆฌ์ผ์ด์
์์ DI ์ปจํ
์ด๋๋ฅผ ์ค์ ํ๋ ๊ณผ์ ์ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. ์ฃผ๋ก Program.cs
๋๋ Startup.cs
ํ์ผ์์ ์ด๋ฃจ์ด์ง๋๋ค.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
// ์ฌ๊ธฐ์์ ์๋น์ค๋ฅผ ๋ฑ๋กํฉ๋๋ค
services.AddTransient<IMyService, MyService>();
});
}
์ ์ฝ๋์์ ConfigureServices
๋ฉ์๋ ๋ด๋ถ์ ์๋น์ค๋ฅผ ๋ฑ๋กํฉ๋๋ค. ์ด๋ ๊ฒ ๋ฑ๋ก๋ ์๋น์ค๋ค์ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฒด์์ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค.
2.3 ์๋น์ค ๋ฑ๋ก ๋ฐฉ๋ฒ
.NET Core DI ์ปจํ ์ด๋๋ ๋ค์ํ ๋ฐฉ์์ผ๋ก ์๋น์ค๋ฅผ ๋ฑ๋กํ ์ ์์ต๋๋ค:
- ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด ๋ฑ๋ก:
services.AddTransient<IMyService, MyService>();
- ๊ตฌ์ฒด ํด๋์ค ๋ฑ๋ก:
services.AddTransient<MyService>();
- ํฉํ ๋ฆฌ ํจ์๋ฅผ ์ฌ์ฉํ ๋ฑ๋ก:
services.AddTransient<IMyService>(sp => new MyService());
- ์ธ์คํด์ค ๋ฑ๋ก:
services.AddSingleton<IMyService>(new MyService());
2.4 ์๋น์ค ํด๊ฒฐ(Resolving)
๋ฑ๋ก๋ ์๋น์ค๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ํด๊ฒฐ(resolve)ํ ์ ์์ต๋๋ค:
- ์์ฑ์ ์ฃผ์
: ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก, ํด๋์ค์ ์์ฑ์์์ ์์กด์ฑ์ ์ฃผ์
๋ฐ์ต๋๋ค.
public class MyController { private readonly IMyService _myService; public MyController(IMyService myService) { _myService = myService; } }
- ์ก์
์ฃผ์
(ASP.NET Core MVC): ์ปจํธ๋กค๋ฌ ์ก์
๋ฉ์๋์์ ์ง์ ์๋น์ค๋ฅผ ์ฃผ์
๋ฐ์ ์ ์์ต๋๋ค.
public IActionResult Index([FromServices] IMyService myService) { // myService ์ฌ์ฉ }
- HttpContext๋ฅผ ํตํ ํด๊ฒฐ: HttpContext๋ฅผ ํตํด ์๋น์ค๋ฅผ ์์ฒญํ ์ ์์ต๋๋ค.
var myService = HttpContext.RequestServices.GetService<IMyService>();
- IServiceProvider๋ฅผ ํตํ ์๋ ํด๊ฒฐ: ํ์ํ ๊ฒฝ์ฐ IServiceProvider๋ฅผ ํตํด ์๋์ผ๋ก ์๋น์ค๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
public class MyClass { public MyClass(IServiceProvider serviceProvider) { var myService = serviceProvider.GetService<IMyService>(); } }
2.5 ์ค์ฝํ์ ์๋ช ์ฃผ๊ธฐ
.NET Core DI ์ปจํ ์ด๋๋ ์ธ ๊ฐ์ง ์ฃผ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ง์ํฉ๋๋ค:
- Transient: ์๋น์ค๊ฐ ์์ฒญ๋ ๋๋ง๋ค ์ ์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค.
- Scoped: ์์ฒญ(HTTP ์์ฒญ ๋ฑ) ๋ฒ์ ๋ด์์ ํ๋์ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํฉ๋๋ค.
- Singleton: ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ์ฃผ๊ธฐ ๋์ ํ๋์ ์ธ์คํด์ค๋ง ์ฌ์ฉํฉ๋๋ค.
๊ฐ ์๋ช ์ฃผ๊ธฐ๋ ๋ค์๊ณผ ๊ฐ์ด ๋ฑ๋กํ ์ ์์ต๋๋ค:
services.AddTransient<ITransientService, TransientService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddSingleton<ISingletonService, SingletonService>();
2.6 DI ์ปจํ ์ด๋์ ๋ด๋ถ ๋์
.NET Core์ DI ์ปจํ ์ด๋๋ ๋ด๋ถ์ ์ผ๋ก ๋ณต์กํ ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ์๋น์ค๊ฐ ์์ฒญ๋๋ฉด, ์ปจํ ์ด๋๋ ๋ค์๊ณผ ๊ฐ์ ๊ณผ์ ์ ๊ฑฐ์นฉ๋๋ค:
- ์์ฒญ๋ ์๋น์ค์ ๋ฑ๋ก ์ ๋ณด๋ฅผ ํ์ธํฉ๋๋ค.
- ์๋น์ค์ ์๋ช ์ฃผ๊ธฐ์ ๋ฐ๋ผ ์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ฑฐ๋ ๊ธฐ์กด ์ธ์คํด์ค๋ฅผ ๋ฐํํฉ๋๋ค.
- ์๋น์ค๊ฐ ๋ค๋ฅธ ์์กด์ฑ์ ๊ฐ์ง๊ณ ์๋ค๋ฉด, ์ฌ๊ท์ ์ผ๋ก ์ด ๊ณผ์ ์ ๋ฐ๋ณตํ์ฌ ๋ชจ๋ ์์กด์ฑ์ ํด๊ฒฐํฉ๋๋ค.
- ์์ ํ ๊ตฌ์ฑ๋ ์๋น์ค ์ธ์คํด์ค๋ฅผ ๋ฐํํฉ๋๋ค.
2.7 ์ฑ๋ฅ ๊ณ ๋ ค์ฌํญ
.NET Core์ DI ์ปจํ ์ด๋๋ ๋งค์ฐ ํจ์จ์ ์ผ๋ก ์ค๊ณ๋์์ง๋ง, ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์๋ ๋ช ๊ฐ์ง ์์๊ฐ ์์ต๋๋ค:
- ์๋น์ค ํด๊ฒฐ ์๊ฐ: ๋ณต์กํ ์์กด์ฑ ๊ทธ๋ํ๋ ์๋น์ค ํด๊ฒฐ ์๊ฐ์ ์ฆ๊ฐ์ํฌ ์ ์์ต๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ: ํนํ Singleton ์๋น์ค์ ๊ฒฝ์ฐ, ๋ง์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- Scoped ์๋น์ค์ ๊ด๋ฆฌ: ๋ง์ ์์ Scoped ์๋น์ค๋ ์์ฒญ ์ฒ๋ฆฌ ์๊ฐ์ ๋๋ฆด ์ ์์ต๋๋ค.
์ด๋ฌํ ์ฑ๋ฅ ์ด์๋ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๋ฌด์ํ ๋งํ ์์ค์ด์ง๋ง, ๋๊ท๋ชจ ์์คํ ์์๋ ์ฃผ์๊ฐ ํ์ํ ์ ์์ต๋๋ค.
2.8 DI ์ปจํ ์ด๋ ํ์ฅ
.NET Core์ DI ์ปจํ ์ด๋๋ ํ์ฅ์ฑ์ด ๋ฐ์ด๋ ์ฌ์ฉ์ ์ ์ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด:
- ์ฌ์ฉ์ ์ ์ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ
- ์กฐ๊ฑด๋ถ ์๋น์ค ๋ฑ๋ก
- ์๋น์ค ๋ฐ์ฝ๋ ์ดํฐ ํจํด ๊ตฌํ
- ์๋น์ค ํฉํ ๋ฆฌ ์ปค์คํฐ๋ง์ด์ง
์ด๋ฌํ ํ์ฅ์ IServiceCollection
์ ํ์ฅ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๊ฑฐ๋, ์ฌ์ฉ์ ์ ์ IServiceProvider
๋ฅผ ๊ตฌํํ์ฌ ์คํํ ์ ์์ต๋๋ค.
- ์๋น์ค ๋ฑ๋ก ์ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋์จํ ๊ฒฐํฉ์ ์ ์งํ์ธ์.
- ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ ์คํ ์ ํํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๊ณผ ์ฑ๋ฅ์ ์ต์ ํํ์ธ์.
- ๋ณต์กํ ์์กด์ฑ ๊ทธ๋ํ๋ ํฉํ ๋ฆฌ ํจํด์ ์ฌ์ฉํ์ฌ ๊ด๋ฆฌํ์ธ์.
- ๋จ์ ํ ์คํธ ์ Mock ๊ฐ์ฒด๋ฅผ ์ฝ๊ฒ ์ฃผ์ ํ ์ ์๋๋ก ์ค๊ณํ์ธ์.
.NET Core์ DI ์ปจํ ์ด๋๋ ๊ฐ๋ ฅํ๋ฉด์๋ ์ ์ฐํ ๋๊ตฌ์ ๋๋ค. ์ด๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ฉด ๋ ๋ชจ๋ํ๋๊ณ , ํ ์คํธํ๊ธฐ ์ฌ์ฐ๋ฉฐ, ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ์ ์์ต๋๋ค.
3. ์๋น์ค ์๋ช ๊ด๋ฆฌ โณ
.NET Core์ DI ์ปจํ ์ด๋์์ ์๋น์ค ์๋ช ๊ด๋ฆฌ๋ ๋งค์ฐ ์ค์ํ ๊ฐ๋ ์ ๋๋ค. ์ ์ ํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ ํํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ์ ์ต์ ํํ๊ณ ๋ฆฌ์์ค๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ์น์ ์์๋ ๊ฐ ์๋น์ค ์๋ช ์ต์ ์ ๋ํด ์์ธํ ์์๋ณด๊ณ , ์ธ์ ์ด๋ค ์ต์ ์ ์ ํํด์ผ ํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
3.1 ์๋น์ค ์๋ช ์ต์
.NET Core DI ์ปจํ ์ด๋๋ ์ธ ๊ฐ์ง ์ฃผ์ ์๋น์ค ์๋ช ์ต์ ์ ์ ๊ณตํฉ๋๋ค:
- Transient (์ผ์์ )
- Scoped (๋ฒ์)
- Singleton (๋จ์ผ)
๊ฐ ์ต์ ์ ์๋น์ค ์ธ์คํด์ค๊ฐ ์์ฑ๋๊ณ ์ฌ์ฌ์ฉ๋๋ ๋ฐฉ์์ ๊ฒฐ์ ํฉ๋๋ค.
3.2 Transient ์๋น์ค
ํน์ง:
- ์๋น์ค๊ฐ ์์ฒญ๋ ๋๋ง๋ค ์๋ก์ด ์ธ์คํด์ค๊ฐ ์์ฑ๋ฉ๋๋ค.
- ๊ฐ์ฅ ์งง์ ์๋ช ์ ๊ฐ์ง๋๋ค.
- ์ํ๋ฅผ ์ ์งํ์ง ์๋ ๊ฐ๋ฒผ์ด ์๋น์ค์ ์ ํฉํฉ๋๋ค.
์ฌ์ฉ ์:
services.AddTransient<IDataProcessor, DataProcessor>();
์ ํฉํ ์๋๋ฆฌ์ค:
- ๊ฐ๋ฒผ์ด ์ํ ๋น์ ์ฅ ์๋น์ค
- ๋งค๋ฒ ์๋ก์ด ์ธ์คํด์ค๊ฐ ํ์ํ ๊ฒฝ์ฐ
- ๋ฉํฐ์ค๋ ๋ฉ ํ๊ฒฝ์์ ์ค๋ ๋ ์์ ์ฑ์ด ํ์ํ ๊ฒฝ์ฐ
3.3 Scoped ์๋น์ค
ํน์ง:
- ์์ฒญ ๋ฒ์(์ผ๋ฐ์ ์ผ๋ก HTTP ์์ฒญ) ๋ด์์ ํ๋์ ์ธ์คํด์ค๊ฐ ๊ณต์ ๋ฉ๋๋ค.
- ๊ฐ์ ์์ฒญ ๋ด์์๋ ๋์ผํ ์ธ์คํด์ค๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.
- ์์ฒญ์ด ์๋ฃ๋๋ฉด ์ธ์คํด์ค๊ฐ ํ๊ธฐ๋ฉ๋๋ค.
์ฌ์ฉ ์:
services.AddScoped<IRepository, Repository>();
์ ํฉํ ์๋๋ฆฌ์ค:
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปจํ ์คํธ
- ์์ฒญ๋ณ ์บ์ฑ
- ์ฌ์ฉ์ ์ธ์ ๊ด๋ จ ์๋น์ค
3.4 Singleton ์๋น์ค
ํน์ง:
- ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ๋์ ๋จ ํ๋์ ์ธ์คํด์ค๋ง ์์ฑ๋ฉ๋๋ค.
- ๋ชจ๋ ์์ฒญ์์ ๋์ผํ ์ธ์คํด์ค๊ฐ ๊ณต์ ๋ฉ๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ค์ผ ์ ์์ง๋ง, ์ค๋ ๋ ์์ ์ฑ์ ์ฃผ์ํด์ผ ํฉ๋๋ค.
์ฌ์ฉ ์:
services.AddSingleton<IConfiguration, Configuration>();
์ ํฉํ ์๋๋ฆฌ์ค:
- ์ ํ๋ฆฌ์ผ์ด์ ์ค์
- ๋ก๊น ์๋น์ค
- ์ธ๋ฉ๋ชจ๋ฆฌ ์บ์
3.5 ์๋ช ์ฃผ๊ธฐ ๋น๊ต
3.6 ์๋ช ์ฃผ๊ธฐ ์ ํ ์ ๊ณ ๋ ค์ฌํญ
์ ์ ํ ์๋น์ค ์๋ช ์ ์ ํํ ๋ ๋ค์ ์ฌํญ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค:
- ์ํ ๊ด๋ฆฌ: ์๋น์ค๊ฐ ์ํ๋ฅผ ์ ์งํด์ผ ํ๋์ง, ์๋๋ฉด ์ํ ๋น์ ์ฅ์ด์ด์ผ ํ๋์ง ๊ณ ๋ คํฉ๋๋ค.
- ์ฑ๋ฅ: ์ธ์คํด์ค ์์ฑ ๋น์ฉ๊ณผ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๊ณ ๋ คํฉ๋๋ค.
- ๋์์ฑ: ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์์ ์์ ์ฑ์ ๊ณ ๋ คํฉ๋๋ค.
- ์์กด์ฑ: ์๋น์ค๊ฐ ์์กดํ๋ ๋ค๋ฅธ ์๋น์ค์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ณ ๋ คํฉ๋๋ค.
- ๋ฆฌ์์ค ๊ด๋ฆฌ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ด๋ ํ์ผ ํธ๋ค๊ณผ ๊ฐ์ ๋ฆฌ์์ค์ ์ ์ ํ ๊ด๋ฆฌ๋ฅผ ๊ณ ๋ คํฉ๋๋ค.
3.7 ์๋ช ์ฃผ๊ธฐ ๊ด๋ จ ์ฃผ์์ฌํญ
Captive Dependency: ๋ ๊ธด ์๋ช ์ ๊ฐ์ง ์๋น์ค๊ฐ ๋ ์งง์ ์๋ช ์ ์๋น์ค์ ์์กดํ๋ ๊ฒฝ์ฐ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ์ ๋๋ค.
// ์๋ชป๋ ์:
services.AddSingleton<IService, Service>(); // Service๋ IRepository์ ์์กด
services.AddScoped<IRepository, Repository>();
// ์ฌ๋ฐ๋ฅธ ์:
services.AddScoped<IService, Service>();
services.AddScoped<IRepository, Repository>();
ํด๊ฒฐ ๋ฐฉ๋ฒ:
- ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ์ ์คํ ์ค๊ณํฉ๋๋ค.
- ํฉํ ๋ฆฌ ํจํด์ ์ฌ์ฉํ์ฌ ์์กด์ฑ์ ๋์ ์ผ๋ก ํด๊ฒฐํฉ๋๋ค.
- IServiceProvider๋ฅผ ์ฃผ์ ๋ฐ์ ํ์ํ ๋ ์๋น์ค๋ฅผ ํด๊ฒฐํฉ๋๋ค.
3.8 ์ฌ์ฉ์ ์ ์ ์๋ช ์ฃผ๊ธฐ
.NET Core DI ์ปจํ ์ด๋๋ ์ฌ์ฉ์ ์ ์ ์๋ช ์ฃผ๊ธฐ๋ ์ง์ํฉ๋๋ค. ํน๋ณํ ์๊ตฌ์ฌํญ์ด ์๋ ๊ฒฝ์ฐ IServiceProviderFactory<TContainerBuilder>๋ฅผ ๊ตฌํํ์ฌ ์ฌ์ฉ์ ์ ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
public class CustomLifetimeManager : IServiceProviderFactory<CustomBuilder>
{
// ๊ตฌํ ๋ด์ฉ
}
// ์ฌ์ฉ
services.AddSingleton<IServiceProviderFactory<CustomBuilder>, CustomLifetimeManager>();
์๋น์ค ์๋ช ๊ด๋ฆฌ๋ .NET Core ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ๊ณผ ์์ ์ฑ์ ํฐ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. ๊ฐ ์๋ช ์ฃผ๊ธฐ ์ต์ ์ ํน์ฑ์ ์ ์ดํดํ๊ณ , ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ตฌ์ฌํญ์ ๋ง๊ฒ ์ ์ ํ ์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์ ์น์ ์์๋ ์ค์ ๋ก ์์กด์ฑ ์ฃผ์ ์ ๊ตฌํํ๋ ๋ค์ํ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
4. ์์กด์ฑ ์ฃผ์ ๊ตฌํ ๋ฐฉ๋ฒ ๐ ๏ธ
์์กด์ฑ ์ฃผ์ (DI)์ ํจ๊ณผ์ ์ผ๋ก ๊ตฌํํ๋ ๊ฒ์ ๊น๋ํ๊ณ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐ ํต์ฌ์ ์ ๋๋ค. ์ด ์น์ ์์๋ .NET Core์์ ์์กด์ฑ ์ฃผ์ ์ ๊ตฌํํ๋ ๋ค์ํ ๋ฐฉ๋ฒ๊ณผ ๊ฐ ๋ฐฉ๋ฒ์ ์ฅ๋จ์ , ๊ทธ๋ฆฌ๊ณ ์ ์ ํ ์ฌ์ฉ ์๋๋ฆฌ์ค์ ๋ํด ์ดํด๋ณด๊ฒ ์ต๋๋ค.
4.1 ์์ฑ์ ์ฃผ์ (Constructor Injection)
์์ฑ์ ์ฃผ์ ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ด๊ณ ๊ถ์ฅ๋๋ DI ๊ตฌํ ๋ฐฉ๋ฒ์ ๋๋ค.
๊ตฌํ ์์:
public class OrderService
{
private readonly IRepository _repository;
private readonly ILogger _logger;
public OrderService(IRepository repository, ILogger logger)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public void ProcessOrder(Order order)
{
_logger.Log("Processing order...");
_repository.Save(order);
}
}
์ฅ์ :
- ์์กด์ฑ์ด ๋ช ํํ๊ฒ ๋๋ฌ๋ฉ๋๋ค.
- ๊ฐ์ฒด ์์ฑ ์์ ์ ๋ชจ๋ ์์กด์ฑ์ด ํด๊ฒฐ๋ฉ๋๋ค.
- ๋ถ๋ณ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
- ๋จ์ ํ ์คํธ๊ฐ ์ฉ์ดํฉ๋๋ค.
๋จ์ :
- ๋ง์ ์์กด์ฑ์ด ์๋ ๊ฒฝ์ฐ ์์ฑ์๊ฐ ๋ณต์กํด์ง ์ ์์ต๋๋ค.
4.2 ์์ฑ ์ฃผ์ (Property Injection)
์์ฑ ์ฃผ์ ์ ์ ํ์ ์ธ ์์กด์ฑ์ ์ฃผ์ ํ ๋ ์ ์ฉํ ์ ์์ต๋๋ค.
๊ตฌํ ์์:
public class EmailService
{
public ILogger Logger { get; set; }
public void SendEmail(string to, string subject, string body)
{
Logger?.Log($"Sending email to {to}");
// ์ด๋ฉ์ผ ์ ์ก ๋ก์ง
}
}
์ฅ์ :
- ์ ํ์ ์์กด์ฑ์ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ๋ฐํ์์ ์์กด์ฑ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
๋จ์ :
- ์์กด์ฑ์ด ๋ช ํํ์ง ์์ ์ ์์ต๋๋ค.
- null ์ฒดํฌ๊ฐ ํ์ํ ์ ์์ต๋๋ค.
- ๋ถ๋ณ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ด๋ ต์ต๋๋ค.
4.3 ๋ฉ์๋ ์ฃผ์ (Method Injection)
๋ฉ์๋ ์ฃผ์ ์ ์์กด์ฑ์ด ๋ฉ์๋ ํธ์ถ ์์๋ง ํ์ํ ๊ฒฝ์ฐ ์ ์ฉํฉ๋๋ค.
๊ตฌํ ์์:
public class ReportGenerator
{
public void GenerateReport(IDataSource dataSource)
{
var data = dataSource.GetData();
// ๋ณด๊ณ ์ ์์ฑ ๋ก์ง
}
}
์ฅ์ :
- ๋ฉ์๋ ํธ์ถ ์์๋ง ์์กด์ฑ์ด ํ์ํ ๊ฒฝ์ฐ ์ ์ฉํฉ๋๋ค.
- ๋ค์ํ ์์กด์ฑ์ ๋์ ์ผ๋ก ์ฃผ์ ํ ์ ์์ต๋๋ค.
๋จ์ :
- ๋ฉ์๋ ํธ์ถ๋ง๋ค ์์กด์ฑ์ ์ ๋ฌํด์ผ ํฉ๋๋ค.
- ํด๋์ค์ ์ํ๋ฅผ ์ ์งํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค.
4.4 ์๋น์ค ๋ก์ผ์ดํฐ ํจํด (Service Locator Pattern)
์๋น์ค ๋ก์ผ์ดํฐ ํจํด์ DI์ ๋์์ผ๋ก ์ฌ์ฉ๋์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก ๊ถ์ฅ๋์ง ์์ต๋๋ค.
๊ตฌํ ์์:
public class OrderProcessor
{
public void ProcessOrder(Order order)
{
var logger = ServiceLocator.Current.GetInstance<ILogger>();
var repository = ServiceLocator.Current.GetInstance<IRepository>();
logger.Log("Processing order...");
repository.Save(order);
}
}
์ฅ์ :
- ์์กด์ฑ์ ๋์ ์ผ๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค.
- ๋ ๊ฑฐ์ ์์คํ ์์ DI๋ก ์ ํํ ๋ ์์ ๋ฐฉํธ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋จ์ :
- ์์กด์ฑ์ด ์จ๊ฒจ์ ธ ์์ด ์ฝ๋์ ์๋๋ฅผ ํ์ ํ๊ธฐ ์ด๋ ต์ต๋๋ค.
- ๋จ์ ํ ์คํธ๊ฐ ์ด๋ ค์์ง๋๋ค.
- ์๋น์ค ๋ก์ผ์ดํฐ์ ๋ํ ์์กด์ฑ์ด ์๊น๋๋ค.
4.5 ํฉํ ๋ฆฌ ํจํด์ ํ์ฉํ DI
๋ณต์กํ ๊ฐ์ฒด ์์ฑ ๋ก์ง์ด ํ์ํ ๊ฒฝ์ฐ ํฉํ ๋ฆฌ ํจํด์ DI์ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ตฌํ ์์:
public interface IServiceFactory
{
IService CreateService(ServiceType type);
}
public class ServiceFactory : IServiceFactory
{
private readonly IServiceProvider _serviceProvider;
public ServiceFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IService CreateService(ServiceType type)
{
switch (type)
{
case ServiceType.TypeA:
return _serviceProvider.GetService<ServiceA>();
case ServiceType.TypeB:
return _serviceProvider.GetService<ServiceB>();
default:
throw new ArgumentOutOfRangeException(nameof(type));
}
}
}
public class ComplexService
{
private readonly IServiceFactory _factory;
public ComplexService(IServiceFactory factory)
{
_factory = factory;
}
public void DoSomething(ServiceType type)
{
var service = _factory.CreateService(type);
service.Execute();
}
}
์ฅ์ :
- ๋ณต์กํ ๊ฐ์ฒด ์์ฑ ๋ก์ง์ ์บก์ํํ ์ ์์ต๋๋ค.
- ๋ฐํ์์ ๊ฐ์ฒด ์์ฑ ๋ฐฉ์์ ๊ฒฐ์ ํ ์ ์์ต๋๋ค.
- DI ์ปจํ ์ด๋์ ์ ํตํฉ๋ฉ๋๋ค.
๋จ์ :
- ์ถ๊ฐ์ ์ธ ์ถ์ํ ๊ณ์ธต์ผ๋ก ์ธํด ๋ณต์ก์ฑ์ด ์ฆ๊ฐํ ์ ์์ต๋๋ค.
4.6 ๋ค์ค ๊ตฌํ ์ฃผ์
ํ๋์ ์ธํฐํ์ด์ค์ ๋ํด ์ฌ๋ฌ ๊ตฌํ์ฒด๋ฅผ ์ฃผ์ ํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
๊ตฌํ ์์:
public interface IValidator<T>
{
bool Validate(T entity);
}
public class CompositeValidator<T> : IValidator<T>
{
private readonly IEnumerable<IValidator<T>> _validators;
public CompositeValidator(IEnumerable<IValidator<T>> validators)
{
_validators = validators;
}
public bool Validate(T entity)
{
return _validators.All(v => v.Validate(entity));
}
}
// ์๋น์ค ๋ฑ๋ก
services.AddTransient<IValidator<User>, EmailValidator>();
services.AddTransient<IValidator<User>, AgeValidator>();
services.AddTransient<IValidator<User>, CompositeValidator<User>>();
์ฅ์ :
- ๋์ผํ ์ธํฐํ์ด์ค์ ์ฌ๋ฌ ๊ตฌํ์ ์ ์ฐํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ์๋ก์ด ๊ตฌํ์ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์์ต๋๋ค.
๋จ์ :
- ๊ตฌํ์ด ๋ณต์กํด์ง ์ ์์ต๋๋ค.
- ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค.
4.7 ์กฐ๊ฑด๋ถ DI
๋ฐํ์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ตฌํ์ ์ฃผ์ ํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
๊ตฌํ ์์:
public interface IDataStore { }
public class SqlDataStore : IDataStore { }
public class InMemoryDataStore : IDataStore { }
services.AddTransient<IDataStore>(serviceProvider =>
{
var configuration = serviceProvider.GetService<IConfiguration>();
return configuration["UseInMemoryStore"] == "true"
? new InMemoryDataStore()
: new SqlDataStore();
});
์ฅ์ :
- ๋ฐํ์ ์กฐ๊ฑด์ ๋ฐ๋ผ ์ ์ฐํ๊ฒ ๊ตฌํ์ ์ ํํ ์ ์์ต๋๋ค.
- ์ค์ ๋ณ๊ฒฝ๋ง์ผ๋ก ๋์์ ๋ฐ๊ฟ ์ ์์ต๋๋ค.
๋จ์ :
- ์กฐ๊ฑด ๋ก์ง์ด ๋ณต์กํด์ง ์ ์์ต๋๋ค.
- ํ ์คํธ๊ฐ ๋ ์ด๋ ค์์ง ์ ์์ต๋๋ค.
- ๊ฐ๋ฅํ ํ ์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ์ธ์. ์ด๋ ๊ฐ์ฅ ๋ช ํํ๊ณ ํ ์คํธํ๊ธฐ ์ฌ์ด ๋ฐฉ๋ฒ์ ๋๋ค.
- ์์ฑ ์ฃผ์ ์ ์ ํ์ ์์กด์ฑ์๋ง ์ฌ์ฉํ์ธ์.
- ๋ฉ์๋ ์ฃผ์ ์ ์์กด์ฑ์ด ๋ฉ์๋ ํธ์ถ ์์๋ง ํ์ํ ๊ฒฝ์ฐ์ ์ฌ์ฉํ์ธ์.
- ์๋น์ค ๋ก์ผ์ดํฐ ํจํด์ ๊ฐ๋ฅํ ํผํ์ธ์. ํ์ํ ๊ฒฝ์ฐ ํฉํ ๋ฆฌ ํจํด์ ๊ณ ๋ คํด๋ณด์ธ์.
- ๋ณต์กํ ์์กด์ฑ ๊ทธ๋ํ๋ ํฉํ ๋ฆฌ ํจํด์ด๋ ๋น๋ ํจํด์ ์ฌ์ฉํ์ฌ ๊ด๋ฆฌํ์ธ์.
- ํญ์ SOLID ์์น, ํนํ ๋จ์ผ ์ฑ ์ ์์น(SRP)๊ณผ ์์กด์ฑ ์ญ์ ์์น(DIP)์ ์ผ๋์ ๋์ธ์.
์์กด์ฑ ์ฃผ์ ์ ํจ๊ณผ์ ์ผ๋ก ๊ตฌํํ๋ ๊ฒ์ ํด๋ฆฐ ์ฝ๋ ์์ฑ์ ํต์ฌ์ ๋๋ค. ๊ฐ ์ํฉ์ ๋ง๋ ์ ์ ํ DI ๊ตฌํ ๋ฐฉ๋ฒ์ ์ ํํ๊ณ , ์ฝ๋์ ์ ์ง๋ณด์์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ ํญ์ ๊ณ ๋ คํ์ธ์. ๋ค์ ์น์ ์์๋ ๋ ๊ณ ๊ธ DI ํ ํฌ๋์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
5. ๊ณ ๊ธ DI ํ ํฌ๋ ๐
๊ธฐ๋ณธ์ ์ธ ์์กด์ฑ ์ฃผ์ ๊ตฌํ์ ๋์ด์, ๋ ๋ณต์กํ๊ณ ํน์ํ ์ํฉ์์ ํ์ฉํ ์ ์๋ ๊ณ ๊ธ DI ํ ํฌ๋๋ค์ด ์์ต๋๋ค. ์ด๋ฌํ ํ ํฌ๋๋ค์ ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์ด๋ ํน๋ณํ ์๊ตฌ์ฌํญ์ด ์๋ ํ๋ก์ ํธ์์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
5.1 ๋ฐ์ฝ๋ ์ดํฐ ํจํด (Decorator Pattern)
๋ฐ์ฝ๋ ์ดํฐ ํจํด์ ๊ธฐ์กด ์๋น์ค์ ์ถ๊ฐ ๊ธฐ๋ฅ์ ๋์ ์ผ๋ก ๋ถ์ด๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. .NET Core DI์์๋ ์ด๋ฅผ ์ฐ์ํ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
๊ตฌํ ์์:
public interface INotificationService
{
void SendNotification(string message);
}
public class EmailNotificationService : INotificationService
{
public void SendNotification(string message)
{
Console.WriteLine($"Sending email: {message}");
}
}
public class LoggingDecorator : INotificationService
{
private readonly INotificationService _inner;
private readonly ILogger _logger;
public LoggingDecorator(INotificationService inner, ILogger logger)
{
_inner = inner;
_logger = logger;
}
public void SendNotification(string message)
{
_logger.Log($"Sending notification: {message}");
_inner.SendNotification(message);
}
}
// ์๋น์ค ๋ฑ๋ก
services.AddTransient<INotificationService, EmailNotificationService>();
services.Decorate<INotificationService, LoggingDecorator>();
์ฅ์ :
- ๊ธฐ์กด ์ฝ๋๋ฅผ ์์ ํ์ง ์๊ณ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ์ฌ๋ฌ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์กฐํฉํ์ฌ ๋ณต์กํ ๋์์ ๊ตฌํํ ์ ์์ต๋๋ค.
- ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๋ฅผ ์ด์งํฉ๋๋ค.
5.2 ์ปจํ ์คํธ ๊ธฐ๋ฐ ์์กด์ฑ ํด๊ฒฐ (Context-based Resolution)
๋ฐํ์ ์ปจํ ์คํธ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ตฌํ์ ์ ๊ณตํด์ผ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
๊ตฌํ ์์:
public interface IUserRepository { }
public class SqlUserRepository : IUserRepository { }
public class MongoUserRepository : IUserRepository { }
public class RepositoryFactory
{
private readonly IServiceProvider _serviceProvider;
public RepositoryFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IUserRepository GetRepository(string context)
{
return context switch
{
"SQL" => _serviceProvider.GetService<SqlUserRepository >(),
"Mongo" => _serviceProvider.GetService<MongoUserRepository>(),
_ => throw new ArgumentException("Unknown context", nameof(context))
};
}
}
// ์๋น์ค ๋ฑ๋ก
services.AddTransient<SqlUserRepository>();
services.AddTransient<MongoUserRepository>();
services.AddTransient<RepositoryFactory>();
์ฅ์ :
- ๋ฐํ์์ ์ ์ฐํ๊ฒ ๊ตฌํ์ ์ ํํ ์ ์์ต๋๋ค.
- ๋ค์ค ํ ๋ํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฉํฉ๋๋ค.
5.3 ๋ ์ด์ง ์์กด์ฑ (Lazy Dependencies)
์์กด์ฑ์ด ์ค์ ๋ก ์ฌ์ฉ๋ ๋๊น์ง ๊ทธ ์์ฑ์ ์ง์ฐ์ํค๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
๊ตฌํ ์์:
public class ExpensiveService
{
public void DoSomething() { /* ๋น์ฉ์ด ๋ง์ด ๋๋ ์์
*/ }
}
public class Client
{
private readonly Lazy<ExpensiveService> _expensiveService;
public Client(Lazy<ExpensiveService> expensiveService)
{
_expensiveService = expensiveService;
}
public void DoWork()
{
// ExpensiveService๋ ์ด ์์ ์ ์์ฑ๋ฉ๋๋ค
_expensiveService.Value.DoSomething();
}
}
// ์๋น์ค ๋ฑ๋ก
services.AddTransient<ExpensiveService>();
services.AddTransient(sp => new Lazy<ExpensiveService>(sp.GetRequiredService<ExpensiveService>));
์ฅ์ :
- ๋ฆฌ์์ค๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์ด๊ธฐํ ์๊ฐ์ ์ค์ผ ์ ์์ต๋๋ค.
5.4 ๋ช ๋ช ๋ ์์กด์ฑ (Named Dependencies)
๊ฐ์ ์ธํฐํ์ด์ค์ ์ฌ๋ฌ ๊ตฌํ์ ๊ตฌ๋ถํด์ผ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
๊ตฌํ ์์:
public interface IPaymentGateway { }
public class StripeGateway : IPaymentGateway { }
public class PayPalGateway : IPaymentGateway { }
public class PaymentService
{
private readonly IPaymentGateway _stripeGateway;
private readonly IPaymentGateway _paypalGateway;
public PaymentService(
[FromKeyedServices("Stripe")] IPaymentGateway stripeGateway,
[FromKeyedServices("PayPal")] IPaymentGateway paypalGateway)
{
_stripeGateway = stripeGateway;
_paypalGateway = paypalGateway;
}
}
// ์๋น์ค ๋ฑ๋ก
services.AddKeyedTransient<IPaymentGateway, StripeGateway>("Stripe");
services.AddKeyedTransient<IPaymentGateway, PayPalGateway>("PayPal");
์ฅ์ :
- ๋์ผํ ์ธํฐํ์ด์ค์ ์ฌ๋ฌ ๊ตฌํ์ ๋ช ํํ๊ฒ ๊ตฌ๋ถํ ์ ์์ต๋๋ค.
- ์ค์ ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ตฌํ์ ์ฝ๊ฒ ์ฃผ์ ํ ์ ์์ต๋๋ค.
5.5 ํ๋ก์ ํจํด (Proxy Pattern)
์๋น์ค์ ๋ํ ์ ๊ทผ์ ์ ์ดํ๊ฑฐ๋ ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
๊ตฌํ ์์:
public interface IDatabase
{
void SaveData(string data);
}
public class Database : IDatabase
{
public void SaveData(string data)
{
Console.WriteLine($"Saving data: {data}");
}
}
public class DatabaseProxy : IDatabase
{
private readonly IDatabase _database;
private readonly ILogger _logger;
public DatabaseProxy(IDatabase database, ILogger logger)
{
_database = database;
_logger = logger;
}
public void SaveData(string data)
{
_logger.Log("Before saving data");
_database.SaveData(data);
_logger.Log("After saving data");
}
}
// ์๋น์ค ๋ฑ๋ก
services.AddTransient<IDatabase, Database>();
services.Decorate<IDatabase, DatabaseProxy>();
์ฅ์ :
- ์๋ณธ ๊ฐ์ฒด์ ๋ํ ์ ๊ทผ์ ์ ์ดํ ์ ์์ต๋๋ค.
- ๋ก๊น , ์บ์ฑ ๋ฑ์ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์์ต๋๋ค.
5.6 ์ปดํฌ์งํธ ํจํด (Composite Pattern)
์ฌ๋ฌ ๊ตฌํ์ ํ๋์ ์ธํฐํ์ด์ค๋ก ํตํฉํ๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
๊ตฌํ ์์:
public interface IValidator
{
bool Validate(object data);
}
public class CompositeValidator : IValidator
{
private readonly IEnumerable<IValidator> _validators;
public CompositeValidator(IEnumerable<IValidator> validators)
{
_validators = validators;
}
public bool Validate(object data)
{
return _validators.All(v => v.Validate(data));
}
}
// ์๋น์ค ๋ฑ๋ก
services.AddTransient<IValidator, EmailValidator>();
services.AddTransient<IValidator, PhoneValidator>();
services.AddTransient<IValidator, CompositeValidator>();
์ฅ์ :
- ๋ณต์กํ ๊ฒ์ฆ ๋ก์ง์ ๋จ์ํํ ์ ์์ต๋๋ค.
- ์๋ก์ด ๊ฒ์ฆ ๊ท์น์ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์์ต๋๋ค.
5.7 ํฉํ ๋ฆฌ ํจํด๊ณผ DI์ ๊ฒฐํฉ
๋ณต์กํ ๊ฐ์ฒด ์์ฑ ๋ก์ง์ ์บก์ํํ๋ฉด์ DI์ ์ด์ ์ ํ์ฉํ๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
๊ตฌํ ์์:
public interface IConnectionFactory
{
IDbConnection CreateConnection();
}
public class SqlConnectionFactory : IConnectionFactory
{
private readonly string _connectionString;
public SqlConnectionFactory(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("DefaultConnection");
}
public IDbConnection CreateConnection()
{
return new SqlConnection(_connectionString);
}
}
public class Repository
{
private readonly IConnectionFactory _connectionFactory;
public Repository(IConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public void SaveData(string data)
{
using var connection = _connectionFactory.CreateConnection();
// ๋ฐ์ดํฐ ์ ์ฅ ๋ก์ง
}
}
// ์๋น์ค ๋ฑ๋ก
services.AddSingleton<IConnectionFactory, SqlConnectionFactory>();
services.AddTransient<Repository>();
์ฅ์ :
- ๊ฐ์ฒด ์์ฑ ๋ก์ง์ ์ค์ํํ ์ ์์ต๋๋ค.
- ํ ์คํธ์ ๋ชจ์ ๊ฐ์ฒด ์์ฑ์ด ์ฉ์ดํด์ง๋๋ค.
- ๋ณต์ก์ฑ๊ณผ ์ ์ฐ์ฑ ์ฌ์ด์ ๊ท ํ์ ์ ์งํ์ธ์. ๋๋ก๋ ๊ฐ๋จํ ํด๊ฒฐ์ฑ ์ด ๋ ๋์ ์ ์์ต๋๋ค.
- ํ ๋ฉค๋ฒ๋ค๊ณผ ์ฌ์ฉ๋ ํจํด์ ๋ํด ์ถฉ๋ถํ ์ํตํ์ธ์. ๋ฌธ์ํ์ ์ฝ๋ ์ฃผ์์ ์ ์์ฑํ์ธ์.
- ์ฑ๋ฅ์ ๋ฏธ์น๋ ์ํฅ์ ํญ์ ๊ณ ๋ คํ์ธ์. ํนํ ๋ฐํ์์ ์์กด์ฑ์ ํด๊ฒฐํ๋ ๊ฒฝ์ฐ ์ฃผ์๊ฐ ํ์ํฉ๋๋ค.
- ๋จ์ ํ ์คํธ๋ฅผ ํตํด ๋ณต์กํ DI ์ค์ ์ด ์๋๋๋ก ์๋ํ๋์ง ํ์ธํ์ธ์.
- ํ์ํ ๊ฒฝ์ฐ์๋ง ๊ณ ๊ธ ํ ํฌ๋์ ์ฌ์ฉํ์ธ์. ๊ณผ๋ํ ์ถ์ํ๋ ์ฝ๋๋ฅผ ์ดํดํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
์ด๋ฌํ ๊ณ ๊ธ DI ํ ํฌ๋๋ค์ ๋ณต์กํ ์๋๋ฆฌ์ค์์ ์ฝ๋์ ์ ์ฐ์ฑ๊ณผ ํ์ฅ์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. ํ์ง๋ง ๊ฐ ํ ํฌ๋์ ์ฅ๋จ์ ์ ์ ์ดํดํ๊ณ , ํ๋ก์ ํธ์ ์๊ตฌ์ฌํญ์ ๋ง๊ฒ ์ ์ ํ ์ ํํ์ฌ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์ ์น์ ์์๋ DI๋ฅผ ์ฌ์ฉํ ๋์ ์ฑ๋ฅ ์ต์ ํ์ ๋ชจ๋ฒ ์ฌ๋ก์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
6. ์ฑ๋ฅ ์ต์ ํ์ ๋ชจ๋ฒ ์ฌ๋ก ๐
์์กด์ฑ ์ฃผ์ (DI)์ ์ฝ๋์ ์ ์ฐ์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ ํฌ๊ฒ ํฅ์์ํค์ง๋ง, ์๋ชป ์ฌ์ฉํ๋ฉด ์ฑ๋ฅ ์ ํ๋ฅผ ์ด๋ํ ์ ์์ต๋๋ค. ์ด ์น์ ์์๋ .NET Core DI๋ฅผ ์ฌ์ฉํ ๋ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ๊ณผ ์ผ๋ฐ์ ์ธ ๋ชจ๋ฒ ์ฌ๋ก์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
6.1 ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ
6.1.1 ์ ์ ํ ์๋ช ์ฃผ๊ธฐ ์ ํ
์๋น์ค์ ์๋ช ์ฃผ๊ธฐ(Transient, Scoped, Singleton)๋ฅผ ์ ์คํ ์ ํํ์ธ์. ๋ถํ์ํ๊ฒ Transient๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด ์์ฑ ๋น์ฉ์ด ์ฆ๊ฐํ ์ ์์ต๋๋ค.
// ์ข์ ์
services.AddSingleton<IConfiguration, Configuration>();
services.AddScoped<IDbContext, AppDbContext>();
services.AddTransient<IEmailSender, EmailSender>();
6.1.2 ๋ ์ด์ง ๋ก๋ฉ ํ์ฉ
๋ฌด๊ฑฐ์ด ์์กด์ฑ์ ๊ฒฝ์ฐ, Lazy<T>๋ฅผ ์ฌ์ฉํ์ฌ ํ์ํ ๋๋ง ์ด๊ธฐํํ์ธ์.
public class HeavyService
{
private readonly Lazy<IExpensiveResource> _expensiveResource;
public HeavyService(Lazy<IExpensiveResource> expensiveResource)
{
_expensiveResource = expensiveResource;
}
public void DoWork()
{
// ํ์ํ ์์ ์ ์ด๊ธฐํ
var resource = _expensiveResource.Value;
// ์์
์ํ
}
}
6.1.3 ๊ฐ์ฒด ํ๋ง ๊ณ ๋ ค
์์ฃผ ์์ฑ๋๊ณ ํ๊ดด๋๋ ๊ฐ์ฒด์ ๊ฒฝ์ฐ, ๊ฐ์ฒด ํ๋ง์ ๊ณ ๋ คํ์ธ์.
services.AddTransient<IObjectPool<ExpensiveObject>, DefaultObjectPool<ExpensiveObject>>();
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
6.1.4 ์ปดํ์ผ ์์ DI ์ฌ์ฉ
์ฑ๋ฅ์ด ์ค์ํ ๊ฒฝ์ฐ, Source Generators๋ฅผ ์ฌ์ฉํ ์ปดํ์ผ ์์ DI๋ฅผ ๊ณ ๋ คํ์ธ์.
[assembly: InjectableAssembly]
public partial class MyService
{
[Inject] private readonly IRepository _repository;
[Inject]
public MyService() { }
public void DoSomething()
{
_repository.SaveData();
}
}
6.2 ๋ชจ๋ฒ ์ฌ๋ก
6.2.1 ์ธํฐํ์ด์ค ๊ธฐ๋ฐ ์ค๊ณ
๊ตฌ์ฒด์ ์ธ ํด๋์ค ๋์ ์ธํฐํ์ด์ค์ ์์กดํ์ธ์. ์ด๋ ์ ์ฐ์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ ํฅ์์ํต๋๋ค.
public class OrderService
{
private readonly IRepository _repository;
private readonly ILogger _logger;
public OrderService(IRepository repository, ILogger logger)
{
_repository = repository;
_logger = logger;
}
}
6.2.2 ์์ฑ์ ์ฃผ์ ์ ํธ
๊ฐ๋ฅํ ํ ์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ์ธ์. ์ด๋ ์์กด์ฑ์ ๋ช ํํ ํ๊ณ ๋ถ๋ณ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
public class UserService
{
private readonly IUserRepository _userRepository;
private readonly IEmailService _emailService;
public UserService(IUserRepository userRepository, IEmailService emailService)
{
_userRepository = userRepository;
_emailService = emailService;
}
}
6.2.3 ์์กด์ฑ ๊ทธ๋ํ ์ต์ํ
์์กด์ฑ ๊ทธ๋ํ๋ฅผ ๊ฐ๋ฅํ ํ ์๊ฒ ์ ์งํ์ธ์. ๊น์ ์์กด์ฑ ๊ทธ๋ํ๋ ์ฑ๋ฅ ์ ํ์ ๋ณต์ก์ฑ ์ฆ๊ฐ๋ฅผ ์ด๋ํ ์ ์์ต๋๋ค.
// ํผํด์ผ ํ ์
public class DeepService
{
public DeepService(IDependency1 dep1, IDependency2 dep2, IDependency3 dep3, IDependency4 dep4, IDependency5 dep5)
{
// ๋๋ฌด ๋ง์ ์์กด์ฑ
}
}
// ๋ ๋์ ์
public class CompositeService
{
public CompositeService(IServiceGroup serviceGroup)
{
// ์์กด์ฑ ๊ทธ๋ฃนํ
}
}
6.2.4 ์๋น์ค ๋ก์ผ์ดํฐ ํจํด ํผํ๊ธฐ
์๋น์ค ๋ก์ผ์ดํฐ ํจํด์ ์์กด์ฑ์ ์จ๊ธฐ๊ณ ํ ์คํธ๋ฅผ ์ด๋ ต๊ฒ ๋ง๋ค ์ ์์ผ๋ฏ๋ก ๊ฐ๋ฅํ ํผํ์ธ์.
// ํผํด์ผ ํ ์
public class BadExample
{
public void DoSomething(IServiceProvider serviceProvider)
{
var service = serviceProvider.GetService<IMyService>();
service.Execute();
}
}
// ๋ ๋์ ์
public class GoodExample
{
private readonly IMyService _service;
public GoodExample(IMyService service)
{
_service = service;
}
public void DoSomething()
{
_service.Execute();
}
}
6.2.5 ์ ์ ํ ์ถ์ํ ์์ค ์ ์ง
๊ณผ๋ํ ์ถ์ํ๋ ์ฝ๋๋ฅผ ๋ณต์กํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ์ ์ ํ ์์ค์ ์ถ์ํ๋ฅผ ์ ์งํ์ธ์.
// ๊ณผ๋ํ ์ถ์ํ์ ์
public interface IStringManipulator
{
string Manipulate(string input);
}
public class UpperCaseManipulator : IStringManipulator
{
public string Manipulate(string input) => input.ToUpper();
}
// ๋ ๊ฐ๋จํ๊ณ ๋ช
ํํ ์
public static class StringExtensions
{
public static string ToUpperCase(this string input) => input.ToUpper();
}
6.2.6 ์ค์ ์ค์ํ
DI ์ค์ ์ ์ค์ํํ์ฌ ๊ด๋ฆฌํ์ธ์. ์ด๋ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํต๋๋ค.
public static class DependencyInjectionConfig
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
services.AddScoped<IUserService, UserService>();
services.AddScoped<IOrderService, OrderService>();
// ๊ธฐํ ์๋น์ค ๋ฑ๋ก
return services;
}
}
// Startup.cs ๋๋ Program.cs์์
services.AddApplicationServices();
6.2.7 ์ํ ์์กด์ฑ ํผํ๊ธฐ
์ํ ์์กด์ฑ์ ๋ณต์ก์ฑ์ ์ฆ๊ฐ์ํค๊ณ ๋๋ฒ๊น ์ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค. ์ค๊ณ๋ฅผ ์ฌ๊ณ ํ์ฌ ์ํ ์์กด์ฑ์ ์ ๊ฑฐํ์ธ์.
// ํผํด์ผ ํ ์ (์ํ ์์กด์ฑ)
public class A
{
public A(B b) { }
}
public class B
{
public B(A a) { }
}
// ๋ ๋์ ์
public class A
{
public A(IB b) { }
}
public class B : IB
{
public B() { }
}
public interface IB { }
- ์ฑ๋ฅ ์ต์ ํ๋ ์ธก์ ๊ฐ๋ฅํ ๋ฌธ์ ๊ฐ ์์ ๋๋ง ์ํํ์ธ์. premature optimization์ ํผํ์ธ์.
- ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋งน๋ชฉ์ ์ผ๋ก ๋ฐ๋ฅด์ง ๋ง๊ณ , ํ๋ก์ ํธ์ ํน์ฑ๊ณผ ์๊ตฌ์ฌํญ์ ๋ง๊ฒ ์ ์ฉํ์ธ์.
- ํ ๋ด์์ ์ผ๊ด๋ DI ํจํด๊ณผ ๊ท์น์ ์ ํ๊ณ ๋ฌธ์ํํ์ธ์.
- ์ ๊ธฐ์ ์ผ๋ก ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ๊ฒํ ํ๊ณ ์ต์ ํํ์ธ์.
- ์๋ก์ด .NET Core ๋ฒ์ ์ด ์ถ์๋ ๋๋ง๋ค DI ๊ด๋ จ ๊ฐ์ ์ฌํญ์ ํ์ธํ๊ณ ์ ์ฉ์ ๊ณ ๋ คํ์ธ์.
์ด๋ฌํ ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ ์ฉํ๋ฉด, .NET Core DI๋ฅผ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ๊ณผ ์ ์ง๋ณด์์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. ๋ค์ ์น์ ์์๋ ์ค์ ํ๋ก์ ํธ์์ DI๋ฅผ ํ์ฉํ๋ ๊ตฌ์ฒด์ ์ธ ์์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
7. ์ค์ ํ๋ก์ ํธ์์์ DI ํ์ฉ ๐๏ธ
์ด๋ก ์ ์ธ ๊ฐ๋ ์ ๋์ด, ์ค์ ํ๋ก์ ํธ์์ ์์กด์ฑ ์ฃผ์ (DI)์ ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ด ์น์ ์์๋ ๋ค์ํ ์๋๋ฆฌ์ค์ ์์๋ฅผ ํตํด DI์ ์ค์ ์ ์ฉ ๋ฐฉ๋ฒ์ ์์๋ณผ ๊ฒ์ ๋๋ค.
7.1 ์น API ํ๋ก์ ํธ์์์ DI ํ์ฉ
ASP.NET Core Web API ํ๋ก์ ํธ์์ DI๋ฅผ ํ์ฉํ๋ ์์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
// Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IUserService, UserService>();
services.AddSingleton<IEmailService, EmailService>();
services.AddHttpClient<IExternalApiClient, ExternalApiClient>();
}
}
// UserController.cs
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
var user = await _userService.GetUserByIdAsync(id);
if (user == null)
return NotFound();
return Ok(user);
}
}
// UserService.cs
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IEmailService _emailService;
public UserService(IUserRepository userRepository, IEmailService emailService)
{
_userRepository = userRepository;
_emailService = emailService;
}
public async Task<User> GetUserByIdAsync(int id)
{
var user = await _userRepository.GetByIdAsync(id);
if (user != null)
{
await _emailService.SendEmailAsync(user.Email, "User Retrieved", "Your user information was accessed.");
}
return user;
}
}
7.2 ๋ฏธ๋ค์จ์ด์์์ DI ํ์ฉ
ASP.NET Core ๋ฏธ๋ค์จ์ด์์ DI๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
public class CustomMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public CustomMiddleware(RequestDelegate next, ILogger<CustomMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, IUserService userService)
{
_logger.LogInformation("Executing CustomMiddleware");
if (context.Request.Headers.TryGetValue("User-Id", out var userId))
{
var user = await userService.GetUserByIdAsync(int.Parse(userId));
if (user != null)
{
context.Items["CurrentUser"] = user;
}
}
await _next(context);
}
}
// Startup.cs์์ ๋ฏธ๋ค์จ์ด ๋ฑ๋ก
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<CustomMiddleware>();
// ๊ธฐํ ๋ฏธ๋ค์จ์ด ์ค์
}
7.3 ๋ฐฐ๊ฒฝ ์์ ์์์ DI ํ์ฉ
IHostedService๋ฅผ ์ฌ์ฉํ ๋ฐฐ๊ฒฝ ์์ ์์ DI๋ฅผ ํ์ฉํ๋ ์์์ ๋๋ค.
public class DataCleanupService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<DataCleanupService> _logger;
public DataCleanupService(IServiceProvider serviceProvider, ILogger<DataCleanupService> logger)
{
_serviceProvider = serviceProvider;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceProvider.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var dateTimeProvider = scope.ServiceProvider.GetRequiredService<IDateTimeProvider>();
var oldData = await dbContext.TemporaryData
.Where(d => d.CreatedAt < dateTimeProvider.Now.AddDays(-30))
.ToListAsync(stoppingToken);
dbContext.TemporaryData.RemoveRange(oldData);
await dbContext.SaveChangesAsync(stoppingToken);
_logger.LogInformation($"Cleaned up {oldData.Count} old records");
}
await Task.Delay(TimeSpan.FromHours(24), stoppingToken);
}
}
}
// Startup.cs์์ ํธ์คํฐ๋ ์๋น์ค ๋ฑ๋ก
services.AddHostedService<DataCleanupService>();
7.4 ํ ์คํธ์์์ DI ํ์ฉ
๋จ์ ํ ์คํธ์์ DI๋ฅผ ํ์ฉํ์ฌ ์์กด์ฑ์ ๋ชจ์(Mock)ํ๋ ์์์ ๋๋ค.
public class UserServiceTests
{
[Fact]
public async Task GetUserByIdAsync_ShouldReturnUser_WhenUserExists()
{
// Arrange
var mockRepository = new Mock<IUserRepository>();
var mockEmailService = new Mock<IEmailService>();
var expectedUser = new User { Id = 1, Name = "John Doe", Email = "john@example.com" };
mockRepository.Setup(repo => repo.GetByIdAsync(1))
.ReturnsAsync(expectedUser);
var userService = new UserService(mockRepository.Object, mockEmailService.Object);
// Act
var result = await userService.GetUserByIdAsync(1);
// Assert
Assert.Equal(expectedUser, result);
mockEmailService.Verify(email => email.SendEmailAsync(
expectedUser.Email,
It.IsAny<string>(),
It.IsAny<string>()
), Times.Once);
}
}
7.5 ์ค์ ์ฃผ์
IOptions ํจํด์ ์ฌ์ฉํ์ฌ ์ค์ ์ ์ฃผ์ ํ๋ ์์์ ๋๋ค.
public class EmailSettings
{
public string SmtpServer { get; set; }
public int Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
public class EmailService : IEmailService
{
private readonly EmailSettings _settings;
public EmailService(IOptions<EmailSettings> settings)
{
_settings = settings.Value;
}
public async Task SendEmailAsync(string to, string subject, string body)
{
using var client = new SmtpClient(_settings.SmtpServer, _settings.Port)
{
Credentials = new NetworkCredential(_settings.Username, _settings.Password),
EnableSsl = true
};
await client.SendMailAsync(new MailMessage(_settings.Username, to, subject, body));
}
}
// Startup.cs์์ ์ค์ ๋ฑ๋ก
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
services.AddSingleton<IEmailService, EmailService>();
7.6 ๋ค์ค ๊ตฌํ ์ฃผ์
ํ๋์ ์ธํฐํ์ด์ค์ ๋ํด ์ฌ๋ฌ ๊ตฌํ์ ์ฃผ์ ํ๊ณ ์ฌ์ฉํ๋ ์์์ ๋๋ค.
public interface INotificationChannel
{
Task SendNotificationAsync(string message);
}
public class EmailNotificationChannel : INotificationChannel { /* ๊ตฌํ */ }
public class SmsNotificationChannel : INotificationChannel { /* ๊ตฌํ */ }
public class PushNotificationChannel : INotificationChannel { /* ๊ตฌํ */ }
public class NotificationService
{
private readonly IEnumerable<INotificationChannel> _channels;
public NotificationService(IEnumerable<INotificationChannel> channels)
{
_channels = channels;
}
public async Task BroadcastNotificationAsync(string message)
{
foreach (var channel in _channels)
{
await channel.SendNotificationAsync(message );
}
}
}
// Startup.cs์์ ๋ฑ๋ก
services.AddTransient<INotificationChannel, EmailNotificationChannel>();
services.AddTransient<INotificationChannel, SmsNotificationChannel>();
services.AddTransient<INotificationChannel, PushNotificationChannel>();
services.AddTransient<NotificationService>();
7.7 ๋ฐ์ฝ๋ ์ดํฐ ํจํด ํ์ฉ
Scrutor ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ฝ๋ ์ดํฐ ํจํด์ ๊ตฌํํ๋ ์์์ ๋๋ค.
public interface ICacheService
{
Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory);
}
public class RedisCacheService : ICacheService { /* Redis ๊ตฌํ */ }
public class CacheDecorator<T> : ICacheService where T : ICacheService
{
private readonly T _inner;
private readonly ILogger _logger;
public CacheDecorator(T inner, ILogger<CacheDecorator<T>> logger)
{
_inner = inner;
_logger = logger;
}
public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory)
{
_logger.LogInformation($"Cache operation for key: {key}");
return await _inner.GetOrSetAsync(key, factory);
}
}
// Startup.cs์์ ๋ฑ๋ก
services.AddTransient<ICacheService, RedisCacheService>();
services.Decorate<ICacheService, CacheDecorator<ICacheService>>();
7.8 Factory ํจํด ํ์ฉ
๋ฐํ์์ ์ ์ ํ ๊ตฌํ์ ์ ํํ๋ Factory ํจํด์ ์์์ ๋๋ค.
public interface IPaymentProcessor
{
Task ProcessPaymentAsync(decimal amount);
}
public class StripePaymentProcessor : IPaymentProcessor { /* Stripe ๊ตฌํ */ }
public class PayPalPaymentProcessor : IPaymentProcessor { /* PayPal ๊ตฌํ */ }
public interface IPaymentProcessorFactory
{
IPaymentProcessor CreateProcessor(string paymentMethod);
}
public class PaymentProcessorFactory : IPaymentProcessorFactory
{
private readonly IServiceProvider _serviceProvider;
public PaymentProcessorFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IPaymentProcessor CreateProcessor(string paymentMethod)
{
return paymentMethod.ToLower() switch
{
"stripe" => _serviceProvider.GetRequiredService<StripePaymentProcessor>(),
"paypal" => _serviceProvider.GetRequiredService<PayPalPaymentProcessor>(),
_ => throw new ArgumentException($"Unsupported payment method: {paymentMethod}")
};
}
}
// Startup.cs์์ ๋ฑ๋ก
services.AddTransient<StripePaymentProcessor>();
services.AddTransient<PayPalPaymentProcessor>();
services.AddSingleton<IPaymentProcessorFactory, PaymentProcessorFactory>();
7.9 Lazy ์์กด์ฑ ํ์ฉ
๋ฌด๊ฑฐ์ด ์์กด์ฑ์ ์ง์ฐ ๋ก๋ฉํ๋ ์์์ ๋๋ค.
public class HeavyService
{
public HeavyService()
{
// ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์ด๊ธฐํ ์์
Thread.Sleep(5000);
}
public void DoWork() { /* ์์
์ํ */ }
}
public class LightweightService
{
private readonly Lazy<HeavyService> _heavyService;
public LightweightService(Lazy<HeavyService> heavyService)
{
_heavyService = heavyService;
}
public void DoSomething()
{
// HeavyService๊ฐ ์ค์ ๋ก ํ์ํ ์์ ์ ์ด๊ธฐํ
_heavyService.Value.DoWork();
}
}
// Startup.cs์์ ๋ฑ๋ก
services.AddTransient<HeavyService>();
services.AddTransient(sp => new Lazy<HeavyService>(sp.GetRequiredService<HeavyService>));
services.AddTransient<LightweightService>();
7.10 ์ค์ฝํ ๊ด๋ฆฌ
์๋์ผ๋ก ์ค์ฝํ๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ ์์์ ๋๋ค.
public class ScopedOperationService
{
private readonly IServiceScopeFactory _scopeFactory;
public ScopedOperationService(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task PerformScopedOperationAsync()
{
using var scope = _scopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<ScopedOperationService>>();
// ์ค์ฝํ ๋ด์์ ์์
์ํ
var entities = await dbContext.Entities.ToListAsync();
foreach (var entity in entities)
{
// ์ํฐํฐ ์ฒ๋ฆฌ
logger.LogInformation($"Processing entity: {entity.Id}");
}
await dbContext.SaveChangesAsync();
}
}
// Startup.cs์์ ๋ฑ๋ก
services.AddTransient<ScopedOperationService>();
- ํ๋ก์ ํธ์ ๊ตฌ์กฐ์ ์๊ตฌ์ฌํญ์ ๋ง๊ฒ DI ํจํด์ ์ ํํ์ธ์.
- ์ฑ๋ฅ์ ๋ฏผ๊ฐํ ๋ถ๋ถ์์๋ Lazy ๋ก๋ฉ์ด๋ Factory ํจํด์ ๊ณ ๋ คํ์ธ์.
- ๋ณต์กํ ์์กด์ฑ ๊ทธ๋ํ๋ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ฒํ ํ๊ณ ์ต์ ํํ์ธ์.
- ํ ์คํธ ์ฉ์ด์ฑ์ ํญ์ ์ผ๋์ ๋๊ณ ์ค๊ณํ์ธ์.
- ์๋ก์ด ํ ๋ฉค๋ฒ๋ฅผ ์ํด DI ์ค์ ๊ณผ ํจํด์ ๋ํ ๋ฌธ์๋ฅผ ์ ์ง๋ณด์ํ์ธ์.
์ด๋ฌํ ์ค์ ์์๋ค์ ํตํด .NET Core์ DI ์์คํ ์ด ์ผ๋ง๋ ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ์ง ์ ์ ์์ต๋๋ค. ํ๋ก์ ํธ์ ์๊ตฌ์ฌํญ๊ณผ ๋ณต์ก์ฑ์ ๋ฐ๋ผ ์ ์ ํ ํจํด๊ณผ ๊ธฐ๋ฒ์ ์ ํํ์ฌ ์ ์ฉํ๋ฉด, ์ ์ง๋ณด์์ฑ์ด ๋๊ณ ํ ์คํธํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ๋ค์ ์น์ ์์๋ DI์ ๊ด๋ จ๋ ํ ์คํ ์ ๋ต์ ๋ํด ๋ ์์ธํ ์์๋ณด๊ฒ ์ต๋๋ค.
8. ํ ์คํ ๊ณผ DI ๐งช
์์กด์ฑ ์ฃผ์ (DI)์ ๋จ์ ํ ์คํธ์ ํตํฉ ํ ์คํธ๋ฅผ ๋ ์ฝ๊ณ ํจ๊ณผ์ ์ผ๋ก ๋ง๋ญ๋๋ค. ์ด ์น์ ์์๋ DI๋ฅผ ํ์ฉํ ๋ค์ํ ํ ์คํ ์ ๋ต๊ณผ ๊ธฐ๋ฒ์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
8.1 ๋จ์ ํ ์คํธ์ DI
DI๋ฅผ ์ฌ์ฉํ๋ฉด ์์กด์ฑ์ ์ฝ๊ฒ ๋ชจ์(Mock)ํ ์ ์์ด, ๋จ์ ํ ์คํธ๊ฐ ํจ์ฌ ๊ฐ๋จํด์ง๋๋ค.
public class OrderService
{
private readonly IRepository<Order> _orderRepository;
private readonly IPaymentService _paymentService;
public OrderService(IRepository<Order> orderRepository, IPaymentService paymentService)
{
_orderRepository = orderRepository;
_paymentService = paymentService;
}
public async Task<bool> PlaceOrderAsync(Order order)
{
if (await _paymentService.ProcessPaymentAsync(order.TotalAmount))
{
await _orderRepository.AddAsync(order);
return true;
}
return false;
}
}
[Fact]
public async Task PlaceOrderAsync_ShouldReturnTrue_WhenPaymentIsSuccessful()
{
// Arrange
var mockOrderRepository = new Mock<IRepository<Order>>();
var mockPaymentService = new Mock<IPaymentService>();
var order = new Order { TotalAmount = 100 };
mockPaymentService.Setup(s => s.ProcessPaymentAsync(It.IsAny<decimal>()))
.ReturnsAsync(true);
var orderService = new OrderService(mockOrderRepository.Object, mockPaymentService.Object);
// Act
var result = await orderService.PlaceOrderAsync(order);
// Assert
Assert.True(result);
mockOrderRepository.Verify(r => r.AddAsync(order), Times.Once);
}
8.2 ํตํฉ ํ ์คํธ์ DI
ASP.NET Core์ TestServer๋ฅผ ์ฌ์ฉํ์ฌ DI ์ปจํ ์ด๋๊ฐ ์ค์ ๋ ํตํฉ ํ ์คํธ๋ฅผ ์ํํ ์ ์์ต๋๋ค.
public class OrderControllerIntegrationTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
public OrderControllerIntegrationTests(WebApplicationFactory<Startup> factory)
{
_factory = factory;
}
[Fact]
public async Task PlaceOrder_ReturnsSuccessStatusCode()
{
// Arrange
var client = _factory.CreateClient();
var order = new OrderDto { TotalAmount = 100 };
// Act
var response = await client.PostAsJsonAsync("/api/orders", order);
// Assert
response.EnsureSuccessStatusCode();
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
}
}
8.3 ํ ์คํธ์ฉ DI ์ปจํ ์ด๋ ๊ตฌ์ฑ
ํ ์คํธ์์ ์ค์ ๊ตฌํ ๋์ ๋ชจ์ ๊ฐ์ฒด๋ ์ธ๋ฉ๋ชจ๋ฆฌ ๊ตฌํ์ ์ฌ์ฉํ๋๋ก DI ์ปจํ ์ด๋๋ฅผ ์ฌ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปจํ
์คํธ ๋์ ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>));
if (descriptor != null)
{
services.Remove(descriptor);
}
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
});
// ์ค์ ์๋น์ค ๋์ ๋ชจ์ ์๋น์ค ์ฌ์ฉ
services.AddTransient<IPaymentService, MockPaymentService>();
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋
var sp = services.BuildServiceProvider();
using var scope = sp.CreateScope();
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<ApplicationDbContext>();
db.Database.EnsureCreated();
SeedTestData(db);
});
}
private void SeedTestData(ApplicationDbContext context)
{
// ํ
์คํธ ๋ฐ์ดํฐ ์ถ๊ฐ
}
}
8.4 ํ ์คํธ ๋๋ธ ํ์ฉ
DI๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์ํ ํ ์คํธ ๋๋ธ(Test Double)์ ์ฝ๊ฒ ์ ์ฉํ ์ ์์ต๋๋ค.
8.4.1 Stub
public class StubPaymentService : IPaymentService
{
public Task<bool> ProcessPaymentAsync(decimal amount)
{
return Task.FromResult(true); // ํญ์ ์ฑ๊ณต ๋ฐํ
}
}
8.4.2 Mock
var mockPaymentService = new Mock<IPaymentService>();
mockPaymentService.Setup(s => s.ProcessPaymentAsync(It.IsAny<decimal>()))
.ReturnsAsync(true);
8.4.3 Fake
public class FakeRepository<T> : IRepository<T> where T : class
{
private readonly List<T> _entities = new List<T>();
public Task<T> GetByIdAsync(int id)
{
return Task.FromResult(_entities.FirstOrDefault());
}
public Task AddAsync(T entity)
{
_entities.Add(entity);
return Task.CompletedTask;
}
// ๊ธฐํ IRepository ๋ฉ์๋ ๊ตฌํ
}
8.5 ํ ์คํธ ์ปจํ ์ด๋ ํ์ฉ
์ค์ ํ๊ฒฝ๊ณผ ์ ์ฌํ ํตํฉ ํ ์คํธ๋ฅผ ์ํด Docker ์ปจํ ์ด๋๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค.
public class DatabaseFixture : IAsyncLifetime
{
private const string ConnectionString = "Server=localhost;Database=TestDb;User=sa;Password=YourStrong!Passw0rd;";
private readonly TestcontainersContainer _dbContainer;
public DatabaseFixture()
{
_dbContainer = new TestcontainersBuilder<TestcontainersContainer>()
.WithImage("mcr.microsoft.com/mssql/server:2019-latest")
.WithEnvironment("ACCEPT_EULA", "Y")
.WithEnvironment("SA_PASSWORD", "YourStrong!Passw0rd")
.WithPortBinding(1433, true)
.WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(1433))
.Build();
}
public async Task InitializeAsync()
{
await _dbContainer.StartAsync();
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง ์์ฑ ๋ฐ ์ด๊ธฐ ๋ฐ์ดํฐ ์ฝ์
}
public async Task DisposeAsync()
{
await _dbContainer.StopAsync();
}
public string GetConnectionString()
{
return ConnectionString.Replace("localhost", _dbContainer.Hostname);
}
}
public class IntegrationTests : IClassFixture<DatabaseFixture>
{
private readonly DatabaseFixture _fixture;
public IntegrationTests(DatabaseFixture fixture)
{
_fixture = fixture;
}
[Fact]
public async Task TestWithRealDatabase()
{
var connectionString = _fixture.GetConnectionString();
// connectionString์ ์ฌ์ฉํ์ฌ ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํต์ ํ๋ ํ
์คํธ ์ํ
}
}
8.6 ์ฑ๋ฅ ํ ์คํธ์ DI
DI ์ค์ ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ์ ๋ฏธ์น๋ ์ํฅ์ ์ธก์ ํ๋ ์ฑ๋ฅ ํ ์คํธ๋ฅผ ์ํํ ์ ์์ต๋๋ค.
[Benchmark]
public async Task ResolveAndUseService()
{
using var scope = _serviceProvider.CreateScope();
var service = scope.ServiceProvider.GetRequiredService<IMyService>();
await service.DoWorkAsync();
}
8.7 ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง ํฅ์
DI๋ฅผ ์ฌ์ฉํ๋ฉด ์์กด์ฑ์ ์ฝ๊ฒ ๊ต์ฒดํ ์ ์์ด, ๋ค์ํ ์๋๋ฆฌ์ค์ ๋ํ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๋์ผ ์ ์์ต๋๋ค.
[Theory]
[InlineData(true, true)]
[InlineData(false, false)]
public async Task PlaceOrderAsync_ShouldReturnExpectedResult(bool paymentSuccess, bool expectedResult)
{
// Arrange
var mockOrderRepository = new Mock<IRepository<Order>>();
var mockPaymentService = new Mock<IPaymentService>();
var order = new Order { TotalAmount = 100 };
mockPaymentService.Setup(s => s.ProcessPaymentAsync(It.IsAny<decimal>()))
.ReturnsAsync(paymentSuccess);
var orderService = new OrderService(mockOrderRepository.Object, mockPaymentService.Object);
// Act
var result = await orderService.PlaceOrderAsync(order);
// Assert
Assert.Equal(expectedResult, result);
mockOrderRepository.Verify(r => r.AddAsync(order), Times.Exactly(paymentSuccess ? 1 : 0));
}
- ๋จ์ ํ ์คํธ์ ํตํฉ ํ ์คํธ์ ์ ์ ํ ๊ท ํ์ ์ ์งํ์ธ์.
- ํ ์คํธ ๋๋ธ์ ์ฌ์ฉํ ๋๋ ์ค์ ๊ตฌํ์ฒด์์ ์ฐจ์ด๋ฅผ ์ต์ํํ์ธ์.
- ํ ์คํธ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ DI ์ค์ ์ด ํ๋ก๋์ ํ๊ฒฝ๊ณผ ํฌ๊ฒ ๋ค๋ฅด์ง ์๋๋ก ์ฃผ์ํ์ธ์.
- ์ฑ๋ฅ์ ๋ฏผ๊ฐํ ๋ถ๋ถ์ ๋ํด์๋ ๋ฒค์น๋งํฌ ํ ์คํธ๋ฅผ ์ ๊ธฐ์ ์ผ๋ก ์ํํ์ธ์.
- ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ DI ๊ด๋ จ ์ฝ๋์ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๋ชจ๋ํฐ๋งํ์ธ์.
DI๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ ํ ์คํ ์ ๋ต์ ์ฝ๋์ ํ์ง์ ํฌ๊ฒ ํฅ์์ํค๊ณ , ๋ฆฌํฉํ ๋ง๊ณผ ๊ธฐ๋ฅ ์ถ๊ฐ๋ฅผ ๋ ์์ ํ๊ฒ ๋ง๋ญ๋๋ค. ๋ค์ ์น์ ์์๋ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ DI๋ฅผ ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
9. ๋ง์ดํฌ๋ก์๋น์ค์ DI ๐
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ ์์กด์ฑ ์ฃผ์ (DI)์ ๋์ฑ ์ค์ํ ์ญํ ์ ํฉ๋๋ค. ์ด ์น์ ์์๋ ๋ง์ดํฌ๋ก์๋น์ค ํ๊ฒฝ์์ DI๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ ๊ณ ๋ คํด์ผ ํ ์ฌํญ๋ค์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
9.1 ๋ง์ดํฌ๋ก์๋น์ค์์์ DI ์ค์์ฑ
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ DI๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ์ค์ํฉ๋๋ค:
- ์๋น์ค ๊ฐ ๋์จํ ๊ฒฐํฉ ์ ์ง
- ์๋น์ค ๋ ๋ฆฝ์ฑ ๋ฐ ๊ต์ฒด ์ฉ์ด์ฑ ํ๋ณด
- ํ ์คํธ ์ฉ์ด์ฑ ํฅ์
- ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ ์ฆ๊ฐ
- ํ์ฅ์ฑ ๋ฐ ์ ์ง๋ณด์์ฑ ๊ฐ์
9.2 ์๋น์ค ๊ฐ ํต์ ๊ณผ DI
๋ง์ดํฌ๋ก์๋น์ค ๊ฐ ํต์ ์์ DI๋ฅผ ํ์ฉํ๋ ์์์ ๋๋ค.
public interface IUserService
{
Task<UserDto> GetUserAsync(int userId);
}
public class HttpUserService : IUserService
{
private readonly HttpClient _httpClient;
public HttpUserService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<UserDto> GetUserAsync(int userId)
{
var response = await _httpClient.GetAsync($"/api/users/{userId}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<UserDto>();
}
}
// Startup.cs
services.AddHttpClient<IUserService, HttpUserService>(client =>
{
client.BaseAddress = new Uri("https://user-service.example.com");
});
9.3 ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ์ DI
๋์ ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ๋ฅผ DI์ ๊ฒฐํฉํ๋ ์์์ ๋๋ค.
public interface IServiceDiscovery
{
Task<Uri> GetServiceUriAsync(string serviceName);
}
public class ConsulServiceDiscovery : IServiceDiscovery
{
private readonly IConsulClient _consulClient;
public ConsulServiceDiscovery(IConsulClient consulClient)
{
_consulClient = consulClient;
}
public async Task<Uri> GetServiceUriAsync(string serviceName)
{
var response = await _consulClient.Health.Service(serviceName, tag: "production");
var service = response.Response.FirstOrDefault(s => s.Service.Service == serviceName);
return service != null ? new Uri($"http://{service.Service.Address}:{service.Service.Port}") : null;
}
}
public class DynamicHttpClientFactory
{
private readonly IServiceDiscovery _serviceDiscovery;
private readonly IHttpClientFactory _httpClientFactory;
public DynamicHttpClientFactory(IServiceDiscovery serviceDiscovery, IHttpClientFactory httpClientFactory)
{
_serviceDiscovery = serviceDiscovery;
_httpClientFactory = httpClientFactory;
}
public async Task<HttpClient> CreateClientAsync(string serviceName)
{
var serviceUri = await _serviceDiscovery.GetServiceUriAsync(serviceName);
var client = _httpClientFactory.CreateClient();
client.BaseAddress = serviceUri;
return client;
}
}
// Startup.cs
services.AddSingleton<IServiceDiscovery, ConsulServiceDiscovery>();
services.AddSingleton<DynamicHttpClientFactory>();
9.4 ๊ตฌ์ฑ ๊ด๋ฆฌ์ DI
์ค์ ์ง์ค์ ๊ตฌ์ฑ ๊ด๋ฆฌ๋ฅผ DI์ ํตํฉํ๋ ์์์ ๋๋ค.
public interface IConfigurationService
{
Task<T> GetConfigurationAsync<T>(string key);
}
public class ConsulConfigurationService : IConfigurationService
{
private readonly IConsulClient _consulClient;
public ConsulConfigurationService(IConsulClient consulClient)
{
_consulClient = consulClient;
}
public async Task<T> GetConfigurationAsync<T>(string key)
{
var pair = await _consulClient.KV.Get(key);
if (pair.Response == null)
throw new KeyNotFoundException($"Configuration key '{key}' not found.");
var value = Encoding.UTF8.GetString(pair.Response.Value);
return JsonSerializer.Deserialize<T>(value);
}
}
public class EmailService
{
private readonly IConfigurationService _configService;
public EmailService(IConfigurationService configService)
{
_configService = configService;
}
public async Task SendEmailAsync(string to, string subject, string body)
{
var smtpConfig = await _configService.GetConfigurationAsync<SmtpConfiguration>("email/smtp");
// smtpConfig๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฉ์ผ ์ ์ก
}
}
// Startup.cs
services.AddSingleton<IConfigurationService, ConsulConfigurationService>();
services.AddTransient<EmailService>();
9.5 ํ๋ณต์ฑ๊ณผ DI
Polly ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ณต์ฑ ํจํด์ DI์ ํตํฉํ๋ ์์์ ๋๋ค.
public interface IResillientHttpClientFactory
{
HttpClient CreateClient(string name);
}
public class ResillientHttpClientFactory : IResillientHttpClientFactory
{
private readonly IHttpClientFactory _httpClientFactory;
public ResillientHttpClientFactory(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public HttpClient CreateClient(string name)
{
var client = _httpClientFactory.CreateClient(name);
var retryPolicy = Policy<HttpResponseMessage>
.Handle<HttpRequestException>()
.OrResult(msg => !msg.IsSuccessStatusCode)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
var circuitBreakerPolicy = Policy<HttpResponseMessage>
.Handle<HttpRequestException>()
.OrResult(msg => !msg.IsSuccessStatusCode)
.CircuitBreakerAsync(5, TimeSpan.FromMinutes(1));
var policyWrap = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);
client.SendAsync = (request, cancellationToken) =>
policyWrap.ExecuteAsync(() => client.SendAsync(request, cancellationToken));
return client;
}
}
// Startup.cs
services.AddHttpClient();
services.AddSingleton<IResillientHttpClientFactory, ResillientHttpClientFactory>();
9.6 ๋ก๊น ๊ณผ ๋ชจ๋ํฐ๋ง
๋ถ์ฐ ๋ก๊น ๋ฐ ๋ชจ๋ํฐ๋ง ์์คํ ์ DI์ ํตํฉํ๋ ์์์ ๋๋ค.
public interface IDistributedLogger
{
Task LogAsync(LogLevel level, string message, params object[] args);
}
public class ElasticSearchLogger : IDistributedLogger
{
private readonly IElasticClient _elasticClient;
public ElasticSearchLogger(IElasticClient elasticClient)
{
_elasticClient = elasticClient;
}
public async Task LogAsync(LogLevel level, string message, params object[] args)
{
var logEntry = new LogEntry
{
Timestamp = DateTime.UtcNow,
Level = level,
Message = string.Format(message, args),
ServiceName = "MyMicroservice"
};
await _elasticClient.IndexDocumentAsync(logEntry);
}
}
public class OrderService
{
private readonly IDistributedLogger _logger;
public OrderService(IDistributedLogger logger)
{
_logger = logger;
}
public async Task ProcessOrderAsync(Order order)
{
await _logger.LogAsync(LogLevel.Information, "Processing order {OrderId}", order.Id);
// ์ฃผ๋ฌธ ์ฒ๋ฆฌ ๋ก์ง
}
}
// Startup.cs
services.AddSingleton<IElasticClient>(sp =>
{
var settings = new ConnectionSettings(new Uri("http://elasticsearch:9200"))
.DefaultIndex("logs");
return new ElasticClient(settings);
});
services.AddSingleton<IDistributedLogger, ElasticSearchLogger>();
9.7 ํธ๋์ญ์ ๊ด๋ฆฌ
๋ถ์ฐ ํธ๋์ญ์ ์ DI์ ํจ๊ป ์ฌ์ฉํ๋ ์์์ ๋๋ค.
public interface IDistributedTransactionManager
{
Task<IDisposable> Be ginTransactionAsync();
Task CommitAsync(IDisposable transactionScope);
Task RollbackAsync(IDisposable transactionScope);
}
public class DistributedTransactionManager : IDistributedTransactionManager
{
private readonly IServiceProvider _serviceProvider;
public DistributedTransactionManager(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task<idisposable> BeginTransactionAsync()
{
// ๋ถ์ฐ ํธ๋์ญ์
์์ ๋ก์ง
return new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
}
public async Task CommitAsync(IDisposable transactionScope)
{
var scope = transactionScope as TransactionScope;
scope?.Complete();
await Task.CompletedTask;
}
public async Task RollbackAsync(IDisposable transactionScope)
{
var scope = transactionScope as TransactionScope;
scope?.Dispose();
await Task.CompletedTask;
}
}
public class OrderProcessingService
{
private readonly IDistributedTransactionManager _transactionManager;
private readonly IOrderRepository _orderRepository;
private readonly IPaymentService _paymentService;
public OrderProcessingService(
IDistributedTransactionManager transactionManager,
IOrderRepository orderRepository,
IPaymentService paymentService)
{
_transactionManager = transactionManager;
_orderRepository = orderRepository;
_paymentService = paymentService;
}
public async Task ProcessOrderAsync(Order order)
{
using var transaction = await _transactionManager.BeginTransactionAsync();
try
{
await _orderRepository.SaveAsync(order);
await _paymentService.ProcessPaymentAsync(order.TotalAmount);
await _transactionManager.CommitAsync(transaction);
}
catch
{
await _transactionManager.RollbackAsync(transaction);
throw;
}
}
}
// Startup.cs
services.AddSingleton<idistributedtransactionmanager distributedtransactionmanager>();
</idistributedtransactionmanager></idisposable>
9.8 ์๋น์ค ๋ฉ์์ DI
์๋น์ค ๋ฉ์(์: Istio)์ DI๋ฅผ ํตํฉํ๋ ์์์ ๋๋ค.
public interface IServiceMesh
{
Task<string> GetServiceEndpointAsync(string serviceName);
}
public class IstioServiceMesh : IServiceMesh
{
private readonly HttpClient _httpClient;
public IstioServiceMesh(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<string> GetServiceEndpointAsync(string serviceName)
{
var response = await _httpClient.GetAsync($"http://istio-pilot.istio-system:8080/v1/registration/{serviceName}");
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
// Istio ์๋ต ํ์ฑ ๋ฐ ์๋ํฌ์ธํธ ๋ฐํ
return "http://service-endpoint";
}
}
public class ServiceClient
{
private readonly IServiceMesh _serviceMesh;
private readonly IHttpClientFactory _httpClientFactory;
public ServiceClient(IServiceMesh serviceMesh, IHttpClientFactory httpClientFactory)
{
_serviceMesh = serviceMesh;
_httpClientFactory = httpClientFactory;
}
public async Task<string> CallServiceAsync(string serviceName, string endpoint)
{
var serviceEndpoint = await _serviceMesh.GetServiceEndpointAsync(serviceName);
var client = _httpClientFactory.CreateClient();
var response = await client.GetAsync($"{serviceEndpoint}/{endpoint}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
// Startup.cs
services.AddHttpClient<iservicemesh istioservicemesh>();
services.AddTransient<serviceclient>();
</serviceclient></iservicemesh></string></string></string>
9.9 ํ์ฅ์ฑ๊ณผ DI
๋์ ์ค์ผ์ผ๋ง์ ์ง์ํ๋ ์๋น์ค๋ฅผ DI์ ํจ๊ป ๊ตฌํํ๋ ์์์ ๋๋ค.
public interface ILoadBalancer
{
Task<string> GetNextEndpointAsync(string serviceName);
}
public class RoundRobinLoadBalancer : ILoadBalancer
{
private readonly IServiceDiscovery _serviceDiscovery;
private readonly ConcurrentDictionary<string list>> _serviceEndpoints = new();
private readonly ConcurrentDictionary<string int> _currentIndex = new();
public RoundRobinLoadBalancer(IServiceDiscovery serviceDiscovery)
{
_serviceDiscovery = serviceDiscovery;
}
public async Task<string> GetNextEndpointAsync(string serviceName)
{
if (!_serviceEndpoints.TryGetValue(serviceName, out var endpoints))
{
endpoints = await _serviceDiscovery.GetServiceEndpointsAsync(serviceName);
_serviceEndpoints[serviceName] = endpoints;
}
if (endpoints.Count == 0)
{
throw new InvalidOperationException($"No endpoints available for service {serviceName}");
}
var index = _currentIndex.AddOrUpdate(serviceName, 0, (_, oldValue) => (oldValue + 1) % endpoints.Count);
return endpoints[index];
}
}
public class ScalableServiceClient
{
private readonly ILoadBalancer _loadBalancer;
private readonly IHttpClientFactory _httpClientFactory;
public ScalableServiceClient(ILoadBalancer loadBalancer, IHttpClientFactory httpClientFactory)
{
_loadBalancer = loadBalancer;
_httpClientFactory = httpClientFactory;
}
public async Task<string> CallServiceAsync(string serviceName, string endpoint)
{
var serviceEndpoint = await _loadBalancer.GetNextEndpointAsync(serviceName);
var client = _httpClientFactory.CreateClient();
var response = await client.GetAsync($"{serviceEndpoint}/{endpoint}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
// Startup.cs
services.AddSingleton<iloadbalancer roundrobinloadbalancer>();
services.AddTransient<scalableserviceclient>();
</scalableserviceclient></iloadbalancer></string></string></string></string></string>
9.10 ๋ณด์๊ณผ DI
๋ง์ดํฌ๋ก์๋น์ค ํ๊ฒฝ์์ ๋ณด์์ DI์ ํตํฉํ๋ ์์์ ๋๋ค.
public interface ITokenService
{
Task<string> GetServiceTokenAsync();
}
public class JwtTokenService : ITokenService
{
private readonly HttpClient _httpClient;
private readonly IOptions<authsettings> _authSettings;
public JwtTokenService(HttpClient httpClient, IOptions<authsettings> authSettings)
{
_httpClient = httpClient;
_authSettings = authSettings;
}
public async Task<string> GetServiceTokenAsync()
{
var response = await _httpClient.PostAsJsonAsync(_authSettings.Value.TokenEndpoint, new
{
client_id = _authSettings.Value.ClientId,
client_secret = _authSettings.Value.ClientSecret,
grant_type = "client_credentials"
});
response.EnsureSuccessStatusCode();
var tokenResponse = await response.Content.ReadFromJsonAsync<tokenresponse>();
return tokenResponse.AccessToken;
}
}
public class SecureServiceClient
{
private readonly ITokenService _tokenService;
private readonly IHttpClientFactory _httpClientFactory;
public SecureServiceClient(ITokenService tokenService, IHttpClientFactory httpClientFactory)
{
_tokenService = tokenService;
_httpClientFactory = httpClientFactory;
}
public async Task<string> CallSecureServiceAsync(string serviceUrl, string endpoint)
{
var token = await _tokenService.GetServiceTokenAsync();
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetAsync($"{serviceUrl}/{endpoint}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
// Startup.cs
services.AddHttpClient<itokenservice jwttokenservice>();
services.AddTransient<secureserviceclient>();
services.Configure<authsettings>(Configuration.GetSection("AuthSettings"));
</authsettings></secureserviceclient></itokenservice></string></tokenresponse></string></authsettings></authsettings></string>
- ์๋น์ค ๊ฐ ํต์ ์ ์ฌ์ฉ๋๋ ํด๋ผ์ด์ธํธ๋ฅผ ์ถ์ํํ๊ณ DI๋ฅผ ํตํด ์ฃผ์ ํ์ธ์.
- ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ, ๋ก๋ ๋ฐธ๋ฐ์ฑ, ํ๋ณต์ฑ ํจํด ๋ฑ์ DI ์ปจํ ์ด๋๋ฅผ ํตํด ์ค์์์ ๊ด๋ฆฌํ์ธ์.
- ๊ตฌ์ฑ, ๋ก๊น , ๋ชจ๋ํฐ๋ง ๋ฑ์ ํฌ๋ก์ค์ปคํ ๊ด์ฌ์ฌ๋ฅผ DI๋ฅผ ํตํด ์ผ๊ด๋๊ฒ ์ฒ๋ฆฌํ์ธ์.
- ๋ณด์ ๊ด๋ จ ๋ก์ง์ DI๋ฅผ ํตํด ์ถ์ํํ์ฌ ์ฌ์ฌ์ฉ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ด์ธ์.
- ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ์ ์์กด์ฑ์ ์ต์ํํ๊ณ , ํ์ํ ๊ฒฝ์ฐ DI๋ฅผ ํตํด ๋์จํ๊ฒ ๊ฒฐํฉํ์ธ์.
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ DI๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ฉด, ์๋น์ค ๊ฐ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ํ์ฅ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. ๊ฐ ์๋น์ค์ ๋ ๋ฆฝ์ฑ์ ์ ์งํ๋ฉด์๋ ๊ณตํต ๊ด์ฌ์ฌ๋ฅผ ์ผ๊ด๋๊ฒ ์ฒ๋ฆฌํ ์ ์๊ฒ ๋ฉ๋๋ค.
10. ๊ฒฐ๋ก ๋ฐ ํฅํ ์ ๋ง ๐ฎ
์ง๊ธ๊น์ง .NET Core์ ์์กด์ฑ ์ฃผ์ (DI) ์ปจํ ์ด๋์ ๋ํด ๊น์ด ์๊ฒ ์ดํด๋ณด์์ต๋๋ค. DI๋ ํ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์์ ํ์์ ์ธ ๊ธฐ์ ์ด๋ฉฐ, .NET Core๋ ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ DI ์์คํ ์ ์ ๊ณตํฉ๋๋ค. ์ด์ ์ฐ๋ฆฌ๊ฐ ํ์ตํ ๋ด์ฉ์ ์ ๋ฆฌํ๊ณ , ์์ผ๋ก์ ์ ๋ง์ ๋ํด ๋ ผ์ํด ๋ณด๊ฒ ์ต๋๋ค.
10.1 ์ฃผ์ ๋ด์ฉ ์์ฝ
- DI์ ๊ธฐ๋ณธ ๊ฐ๋ : ์์กด์ฑ ์ฃผ์ ์ ํต์ฌ ์๋ฆฌ์ ์ด์ ์ ๋ํด ํ์ตํ์ต๋๋ค.
- .NET Core DI ์ปจํ ์ด๋: .NET Core์์ ์ ๊ณตํ๋ DI ์ปจํ ์ด๋์ ํน์ง๊ณผ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค.
- ์๋น์ค ์๋ช ๊ด๋ฆฌ: Transient, Scoped, Singleton ๋ฑ ๋ค์ํ ์๋น์ค ์๋ช ์ต์ ๊ณผ ๊ทธ ํ์ฉ๋ฒ์ ์ดํดํ์ต๋๋ค.
- DI ๊ตฌํ ๋ฐฉ๋ฒ: ์์ฑ์ ์ฃผ์ , ์์ฑ ์ฃผ์ , ๋ฉ์๋ ์ฃผ์ ๋ฑ ๋ค์ํ DI ๊ตฌํ ๋ฐฉ๋ฒ์ ํ์ตํ์ต๋๋ค.
- ๊ณ ๊ธ DI ํ ํฌ๋: ๋ฐ์ฝ๋ ์ดํฐ ํจํด, ํฉํ ๋ฆฌ ํจํด ๋ฑ ๊ณ ๊ธ DI ๊ธฐ๋ฒ์ ํ๊ตฌํ์ต๋๋ค.
- ์ฑ๋ฅ ์ต์ ํ์ ๋ชจ๋ฒ ์ฌ๋ก: DI ์ฌ์ฉ ์ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์์๋ณด์์ต๋๋ค.
- ์ค์ ํ๋ก์ ํธ ์ ์ฉ: ๋ค์ํ ์ค์ ์๋๋ฆฌ์ค์์ DI๋ฅผ ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง ์ดํด๋ณด์์ต๋๋ค.
- ํ ์คํ ๊ณผ DI: DI๋ฅผ ํ์ฉํ ํจ๊ณผ์ ์ธ ๋จ์ ํ ์คํธ์ ํตํฉ ํ ์คํธ ๋ฐฉ๋ฒ์ ํ์ตํ์ต๋๋ค.
- ๋ง์ดํฌ๋ก์๋น์ค์ DI: ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ DI๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ํ๊ตฌํ์ต๋๋ค.
10.2 DI์ ์ค์์ฑ
์์กด์ฑ ์ฃผ์ ์ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ํ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์์ ๋งค์ฐ ์ค์ํฉ๋๋ค:
- ์ฝ๋์ ์ ์ฐ์ฑ ํฅ์: DI๋ฅผ ํตํด ๊ตฌ์ฒด์ ์ธ ๊ตฌํ์ ์์กดํ์ง ์๊ณ ์ถ์ํ์ ์์กดํ ์ ์์ด, ์ฝ๋์ ์ ์ฐ์ฑ์ด ํฌ๊ฒ ํฅ์๋ฉ๋๋ค.
- ํ ์คํธ ์ฉ์ด์ฑ: ์์กด์ฑ์ ์ฝ๊ฒ ๋ชจ์(Mock)ํ ์ ์์ด, ๋จ์ ํ ์คํธ๊ฐ ํจ์ฌ ์ฌ์์ง๋๋ค.
- ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ: DI๋ ๊ฐ์ฒด ์์ฑ๊ณผ ์ฌ์ฉ์ ๋ถ๋ฆฌํ์ฌ ๋จ์ผ ์ฑ ์ ์์น์ ์งํค๋ ๋ฐ ๋์์ ์ค๋๋ค.
- ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ: ์์กด์ฑ์ ์ถ์ํํจ์ผ๋ก์จ ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ์ด ๋์์ง๋๋ค.
- ์ ์ง๋ณด์์ฑ ํฅ์: ๋์จํ ๊ฒฐํฉ์ ํตํด ์ฝ๋์ ์ ์ง๋ณด์๊ฐ ์ฌ์์ง๋๋ค.
10.3 .NET Core DI์ ๊ฐ์
.NET Core์ DI ์์คํ ์ ๋ค์๊ณผ ๊ฐ์ ๊ฐ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค:
- ๋ด์ฅํ ์๋ฃจ์ : ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ด ํ๋ ์์ํฌ์ ๊ธฐ๋ณธ์ผ๋ก ํฌํจ๋์ด ์์ต๋๋ค.
- ์ฑ๋ฅ ์ต์ ํ: Microsoft์ ์ํด ์ง์์ ์ผ๋ก ์ต์ ํ๋์ด ๋์ ์ฑ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- ํ์ฅ์ฑ: ์ฌ์ฉ์ ์ ์ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์๋ ํ์ฅ ํฌ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ํตํฉ์ฑ: ASP.NET Core ๋ฐ ๋ค๋ฅธ .NET ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๊ณผ ๊ธด๋ฐํ๊ฒ ํตํฉ๋์ด ์์ต๋๋ค.
- ์ง์์ ์ธ ๊ฐ์ : ๊ฐ .NET ๋ฒ์ ๋ง๋ค ์๋ก์ด ๊ธฐ๋ฅ๊ณผ ๊ฐ์ ์ฌํญ์ด ์ถ๊ฐ๋๊ณ ์์ต๋๋ค.
10.4 ํฅํ ์ ๋ง
์์กด์ฑ ์ฃผ์ ๊ณผ .NET Core DI ์์คํ ์ ๋ฏธ๋๋ ๋งค์ฐ ๋ฐ์ ๋ณด์ ๋๋ค. ๋ค์๊ณผ ๊ฐ์ ํธ๋ ๋์ ๋ฐ์ ์ด ์์๋ฉ๋๋ค:
- ์ปดํ์ผ ์์ ์ต์ ํ: ์์ค ์ ๋๋ ์ดํฐ๋ฅผ ํ์ฉํ ์ปดํ์ผ ์์ DI ์ต์ ํ๊ฐ ๋์ฑ ๋ฐ์ ํ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค.
- ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ํตํฉ: ์ฟ ๋ฒ๋คํฐ์ค, ์๋น์ค ๋ฉ์ ๋ฑ ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ๊ธฐ์ ๊ณผ์ ๋ ๊น์ ํตํฉ์ด ์ด๋ฃจ์ด์ง ๊ฒ์ ๋๋ค.
- AI/ML ํตํฉ: ์ธ๊ณต์ง๋ฅ๊ณผ ๋จธ์ ๋ฌ๋ ์๋น์ค๋ฅผ ๋ ์ฝ๊ฒ ์ฃผ์ ํ๊ณ ์ฌ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ด ๊ฐ๋ฐ๋ ๊ฒ์ ๋๋ค.
- ํฌ๋ก์ค ํ๋ซํผ ์ง์ ๊ฐํ: .NET์ ํฌ๋ก์ค ํ๋ซํผ ํน์ฑ์ ๋ง์ถฐ ๋ค์ํ ํ๊ฒฝ์์์ DI ์ง์์ด ๊ฐํ๋ ๊ฒ์ ๋๋ค.
- ์ฑ๋ฅ ํฅ์: ์ง์์ ์ธ ์ต์ ํ๋ฅผ ํตํด DI ์์คํ ์ ์ฑ๋ฅ์ด ๋์ฑ ํฅ์๋ ๊ฒ์ ๋๋ค.
- ๋ณด์ ๊ฐํ: ์์กด์ฑ ์ฃผ์ ์ ํตํ ๋ณด์ ๊ธฐ๋ฅ ํตํฉ์ด ๋์ฑ ๊ฐํ๋ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค.
- ๊ฐ๋ฐ์ ๊ฒฝํ ๊ฐ์ : DI ์ค์ ๊ณผ ์ฌ์ฉ์ ๋์ฑ ์ง๊ด์ ์ด๊ณ ์ฝ๊ฒ ๋ง๋๋ ๋๊ตฌ์ ๊ธฐ๋ฅ์ด ๊ฐ๋ฐ๋ ๊ฒ์ ๋๋ค.
10.5 ๊ฐ๋ฐ์๋ฅผ ์ํ ์กฐ์ธ
์์กด์ฑ ์ฃผ์ ๊ณผ .NET Core DI๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ ์กฐ์ธ์ ๋๋ฆฝ๋๋ค:
- ์ง์์ ์ธ ํ์ต: DI ํจํด๊ณผ .NET Core์ ์๋ก์ด ๊ธฐ๋ฅ์ ๋ํด ์ง์์ ์ผ๋ก ํ์ตํ์ธ์.
- ์ค์ ํ๋ก์ ํธ์ ์ ์ฉ: ์ด๋ก ์ ์ง์์ ์ค์ ํ๋ก์ ํธ์ ์ ๊ทน์ ์ผ๋ก ์ ์ฉํด ๋ณด์ธ์.
- ์ปค๋ฎค๋ํฐ ์ฐธ์ฌ: .NET ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํ์ฌ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ๊ฒฝํ์ ๊ณต์ ํ์ธ์.
- ์ฝ๋ ๋ฆฌ๋ทฐ: ๋๋ฃ๋ค๊ณผ DI ๊ด๋ จ ์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ์์ฃผ ํ์ฌ ์ต์ ์ ๋ฐฉ๋ฒ์ ์ฐพ์๊ฐ์ธ์.
- ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: DI ์ฌ์ฉ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ์ ๋ฏธ์น๋ ์ํฅ์ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ์ธ์.
- ์ค๊ณ ์์น ์ค์: SOLID ์์น ๋ฑ ๊ฐ์ฒด ์งํฅ ์ค๊ณ ์์น์ ํญ์ ์ผ๋์ ๋์ธ์.
- ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ: DI๋ฅผ ํ์ฉํ ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ(TDD)์ ์ค์ฒํด ๋ณด์ธ์.
์์กด์ฑ ์ฃผ์ ๊ณผ .NET Core DI์ ๋ํ ์ฐ๋ฆฌ์ ์ฌ์ ์ด ์ฌ๊ธฐ์ ๋๋ฉ๋๋ค. ์ด ์ง์์ด ์ฌ๋ฌ๋ถ์ ์ํํธ์จ์ด ๊ฐ๋ฐ ์ฌ์ ์ ํฐ ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ํญ์ ํ์ตํ๊ณ , ์คํํ๊ณ , ๊ฐ์ ํ๋ ์์ธ๋ฅผ ์์ง ๋ง์ธ์. ํ์ด์ ๋น๋๋ค!
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ