Search

μ˜μ‘΄μ„± μ£Όμž… (DI)

μ˜μ‘΄μ„± μ£Όμž… (DI; Dependency Injection)

μ˜μ‘΄μ„± μ£Όμž…(DI)은 μ†Œν”„νŠΈμ›¨μ–΄ κ°œλ°œμ—μ„œ μ€‘μš”ν•œ κ°œλ…μž…λ‹ˆλ‹€. DIλŠ” μ»΄ν¬λ„ŒνŠΈ κ°„μ˜ μ˜μ‘΄μ„±μ„ μ™ΈλΆ€μ—μ„œ μ£Όμž…ν•¨μœΌλ‘œμ¨ λŠμŠ¨ν•œ 결합을 μœ μ§€ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€. 이λ₯Ό 톡해 μ½”λ“œμ˜ μœ μ—°μ„±κ³Ό μž¬μ‚¬μš©μ„±μ„ 높일 수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€ν”„λ§ DI

μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬μ—μ„œλŠ” DIλ₯Ό μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆλŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. μŠ€ν”„λ§ DI μ»¨ν…Œμ΄λ„ˆκ°€ 객체 κ°„μ˜ μ˜μ‘΄μ„±μ„ κ΄€λ¦¬ν•˜κ³  ν•„μš”ν•œ 의쑴 객체λ₯Ό μ£Όμž…ν•΄μ€λ‹ˆλ‹€. 이λ₯Ό 톡해 κ°œλ°œμžλŠ” 객체λ₯Ό μƒμ„±ν•˜κ³  μ˜μ‘΄μ„±μ„ κ΄€λ¦¬ν•˜λŠ” 뢀뢄에 집쀑할 ν•„μš” 없이 λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— 집쀑할 수 μžˆμŠ΅λ‹ˆλ‹€.

Ioc μ»¨ν…Œμ΄λ„ˆ

Ioc μ»¨ν…Œμ΄λ„ˆλŠ” Inversion of Control(μ œμ–΄μ˜ μ—­μ „) μ»¨ν…Œμ΄λ„ˆλ‘œ, μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬μ˜ ν•΅μ‹¬μž…λ‹ˆλ‹€. Ioc μ»¨ν…Œμ΄λ„ˆλŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ ꡬ성 μš”μ†Œλ“€μ„ κ΄€λ¦¬ν•˜λ©°, 객체의 생성과 μ˜μ‘΄μ„± μ£Όμž…μ„ λ‹΄λ‹Ήν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 κ°œλ°œμžλŠ” 객체의 생λͺ…주기와 μ˜μ‘΄μ„±μ„ 직접 κ΄€λ¦¬ν•˜μ§€ μ•Šμ•„λ„ λ˜λ―€λ‘œ 개발 생산성과 μœ μ§€ λ³΄μˆ˜μ„±μ„ ν–₯μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

μ˜μ‘΄μ„± μ£Όμž…ν•˜λŠ” 방법

1.
빈 μ •μ˜
2.
빈 등둝
3.
μ˜μ‘΄μ„± μžλ™ μ£Όμž…

빈 μ •μ˜

: κ°œλ°œμžκ°€ μŠ€ν”„λ§ IoC μ»¨ν…Œμ΄λ„ˆμ— μ˜ν•΄ 관리될 객체에 λŒ€ν•œ 정보λ₯Ό μ œκ³΅ν•˜λŠ” 것

방법

β€’
XML 기반 μ„€μ •
β€’
μ–΄λ…Έν…Œμ΄μ…˜ 기반 μ„€μ •
β€’
Java Config 기반 μ„€μ •

XML 기반 μ„€μ •

XML νŒŒμΌμ„ μ‚¬μš©ν•˜μ—¬ λΉˆμ„ μ •μ˜ν•˜λŠ” 방법. <bean> νƒœκ·Έλ₯Ό μ‚¬μš©ν•˜μ—¬ 객체의 클래슀, 이름, λ²”μœ„ 등을 μ§€μ •ν•©λ‹ˆλ‹€.
μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬μ—μ„œλŠ” 빈 μ •μ˜μ™€ μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ”μ„ XML μ„€μ • νŒŒμΌμ„ μ‚¬μš©ν•œλ‹€.
μŠ€ν”„λ§ λΆ€νŠΈμ—μ„œλŠ” μžλ™ μ„€μ • (Auto Configuration) κΈ°λŠ₯이 μžˆμ–΄μ„œ, XML μ„€μ • νŒŒμΌμ— μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ” 섀정을 ν•  ν•„μš”κ°€ μ—†κ³ , XML μ„€μ • νŒŒμΌμ„ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€.
μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬(ONLY)
root-context.xml λ˜λŠ” servlet-context.xml νŒŒμΌμ—μ„œ 빈 μ •μ˜λ₯Ό ν•©λ‹ˆλ‹€.
β€’
root-context.xml : μŠ€ν”„λ§ IoC μ»¨ν…Œμ΄λ„ˆλ₯Ό μ΄ˆκΈ°ν™”ν•˜κ³  μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ „λ°˜μ μΈ μ„€μ •κ³Ό λΉˆμ„ ν¬ν•¨ν•©λ‹ˆλ‹€. 이 νŒŒμΌμ€ 전역적인 빈 μ •μ˜ 및 μ„œλΉ„μŠ€ 계측, 데이터 μ•‘μ„ΈμŠ€ 계측과 같은 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ „λ°˜μ— 걸친 λΉˆμ„ μ„€μ •ν•©λ‹ˆλ‹€.
β€’
servlet-context.xml : μ„œλΈ”λ¦Ώ 기반 μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©λ˜λ©°, 주둜 μ›Ή 계측과 κ΄€λ ¨λœ λΉˆλ“€μ„ μ •μ˜ν•©λ‹ˆλ‹€. 이 νŒŒμΌμ€ 주둜 μ›Ή μ»΄ν¬λ„ŒνŠΈ(컨트둀러, λ·° 리쑸버 λ“±)와 κ΄€λ ¨λœ λΉˆμ„ μ„€μ •ν•©λ‹ˆλ‹€.
μ˜ˆμ‹œ
<!-- root-context.xml --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myBean" class="com.example.MyBean" /> </beans>
XML
볡사
package com.example; public class MyBean { private String name; private int age; public MyBean() { this.name = "Default Name"; this.age = 0; } public MyBean(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String displayInfo() { return "Name: " + name + ", Age: " + age; } }
Java
볡사

μ–΄λ…Έν…Œμ΄μ…˜ 기반 μ„€μ •

μ–΄λ…Έν…Œμ΄μ…˜
μ—­ν• 
@Component
일반적인 μŠ€ν”„λ§ 빈으둜 μ‚¬μš©λ¨.
@Controller
Spring MVC 컨트둀러둜 μ‚¬μš©λ˜λŠ” 클래슀λ₯Ό λ‚˜νƒ€λƒ„.
@Service
λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ μ²˜λ¦¬ν•˜λŠ” μ„œλΉ„μŠ€ 클래슀λ₯Ό λ‚˜νƒ€λƒ„.
@Repository
데이터 μ•‘μ„ΈμŠ€ 객체 (DAO)λ₯Ό λ‚˜νƒ€λƒ„.
μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬(ONLY)
β€’
servlet-context.xml
<context:component-scan base-package="com.aloha.spring" />
Java
볡사
μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ λΉˆμ„ λ“±λ‘ν•˜λ €λ©΄, servlet-context.xml 에 μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ” νƒœκ·Έλ₯Ό λ“±λ‘ν•΄μ•Όν•œλ‹€.
μŠ€ν”„λ§ λΉˆμ„ 검색할 base-package 속성에 μ§€μ •ν•˜λŠ” νŒ¨ν‚€μ§€ ν•˜μœ„μ˜ 경둜의 μžˆλŠ” μŠ€ν”„λ§ 빈 클래슀λ₯Ό μžλ™μœΌλ‘œ κ²€μƒ‰ν•˜κ³  빈으둜 λ“±λ‘ν•œλ‹€.

@Component

β€’
클래슀
@Component public class MyComponent { }
Java
볡사
μŠ€ν”„λ§ 빈으둜 등둝할 ν΄λž˜μŠ€λŠ” `@Component` μ–΄λ…Έν…Œμ΄μ…˜μ„ λΆ™μ—¬μ£Όλ©΄ μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ” μ‹œ, μΈμ‹λ˜μ–΄ Ioc μ»¨ν…Œμ΄λ„ˆμ— λ“±λ‘λœλ‹€.

@Service

β€’
BoardService.java
@Service public class BoardService { }
Java
볡사
`@Service` μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ μ²˜λ¦¬ν•˜λŠ” μŠ€ν”„λ§ 빈 클래슀둜 μ§€μ •ν•˜μ—¬ Ioc μ»¨ν…Œμ΄ν„°μ— 빈으둜 λ“±λ‘λœλ‹€.

@Repository

β€’
BoardDAO.java
@Repository public class BoardDAO { }
Java
볡사
`@Repository` μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ 데이터 μ•‘μ„ΈμŠ€ κ³„μΈ΅μ˜ ν΄λž˜μŠ€μ— μ§€μ •ν•˜μ—¬ Ioc μ»¨ν…Œμ΄ν„°μ— 빈으둜 λ“±λ‘λœλ‹€.

@Controller

β€’
BoardControler.java
@Controller public class BoardController { }
Java
볡사
`@Controller` μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 컨트둀러 클래슀둜 μ§€μ •ν•˜μ—¬ Ioc μ»¨ν…Œμ΄ν„°μ— 빈으둜 λ“±λ‘λœλ‹€.

Java Config 기반 μ„€μ •

@Configuration

β€’
Config.java
@Configuration // μŠ€ν”„λ§ μ„€μ • 빈으둜 등둝 public class Config { // 1. 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œλ₯Ό μ •μ˜ // 2. λ©”μ†Œλ“œμ— @Bean μ–΄λ…Έν…Œμ΄μ…˜ μ •μ˜ @Bean // IoC μ»¨ν…Œμ΄λ„ˆμ— 빈으둜 등둝 public Board board() { return new Board("제λͺ©", "μž‘μ„±μž", "λ‚΄μš©"); } }
Java
볡사
β€’
@Configuration : 클래슀λ₯Ό μŠ€ν”„λ§μ˜ Java 기반 μ„€μ • 클래슀둜 지정
β€’
@Bean : @Configuration μ–΄λ…Έν…Œμ΄μ…˜μ„ 가진 클래슀 λ‚΄μ—μ„œ λ©”μ„œλ“œμ— λΆ€μ—¬ν•˜μ—¬ ν•΄λ‹Ή λ©”μ„œλ“œκ°€ μŠ€ν”„λ§ 빈(Bean)을 μƒμ„±ν•˜κ³  κ΄€λ¦¬ν•˜λ„λ‘ 지정

빈 등둝

: μŠ€ν”„λ§ IoC μ»¨ν…Œμ΄λ„ˆκ°€ 빈의 μ •μ˜μ— 따라 객체λ₯Ό μƒμ„±ν•˜κ³ , λ“±λ‘ν•˜λŠ” κ³Όμ •

μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ”

XML μ„€μ •, @Component μ–΄λ…Έν…Œμ΄μ…˜, Config 기반 섀정을 μ‚¬μš©ν•˜μ—¬ μžλ™μœΌλ‘œ 빈으둜 λ“±λ‘λ˜λŠ” μ»΄ν¬λ„ŒνŠΈλ₯Ό μŠ€μΊ”ν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 κ°œλ°œμžλŠ” 일일이 λΉˆμ„ λ“±λ‘ν•˜μ§€ μ•Šκ³ λ„ μ»΄ν¬λ„ŒνŠΈλ₯Ό μžλ™μœΌλ‘œ μΈμ‹ν•˜κ³  μ˜μ‘΄μ„±μ„ μ£Όμž…ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬κ°€ μ•Œμ•„μ„œ ν•œλŒ€μš”.

μ˜μ‘΄μ„± μžλ™ μ£Όμž…

: 객체 κ°„μ˜ 관계λ₯Ό μ„€μ •ν•˜κ³ , ν•œ 객체가 λ‹€λ₯Έ 객체λ₯Ό ν•„μš”λ‘œ ν•  λ•Œ, μ»¨ν…Œμ΄λ„ˆ(예: μŠ€ν”„λ§)κ°€ μžλ™μœΌλ‘œ ν•„μš”ν•œ 객체λ₯Ό μ£Όμž…ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ„ μ˜λ―Έν•©λ‹ˆλ‹€.

μ˜μ‘΄μ„± μ£Όμž… μ’…λ₯˜

β€’
κΈ°λ³Έ μ˜μ‘΄μ„± μžλ™ μ£Όμž…
β€’
νƒ€μž… 기반 μ£Όμž…
β€’
μƒμ„±μž μ£Όμž…
β€’
λ©”μ„œλ“œ μ£Όμž…

κΈ°λ³Έ μ˜μ‘΄μ„± μžλ™ μ£Όμž…

β€’
`@Autowired` : μ˜μ‘΄μ„± μžλ™ μ£Όμž… μ–΄λ…Έν…Œμ΄μ…˜
μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ 빈의 μ˜μ‘΄μ„±μ„ μžλ™μœΌλ‘œ ν•΄κ²°ν•˜λ„λ‘ μ§€μ‹œν•©λ‹ˆλ‹€.
@Autowired private MyBean myBean;
Java
볡사

νƒ€μž… 기반 μ£Όμž…

β€’
빈 이름을 μ§€μ •ν•΄μ„œ μ˜μ‘΄μ„±μ„ μ£Όμž…ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.
β—¦
@Autowired
β—¦
@Qualifier("λΉˆμ΄λ¦„")
β—¦
@Component("λΉˆμ΄λ¦„")
β€’
@Autowired : μ˜μ‘΄μ„± μ£Όμž…μ„ μžλ™μœΌλ‘œ μ²˜λ¦¬ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜
β€’
@Qualifier("λΉˆμ΄λ¦„") : μ—¬λŸ¬ 개의 λ™μΌν•œ νƒ€μž…μ˜ 빈 쀑 νŠΉμ • λΉˆμ„ μ§€μ •ν•˜μ—¬ μ£Όμž…ν•  λ•Œ μ‚¬μš©ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜
β€’
@Component("λΉˆμ΄λ¦„") : ν•΄λ‹Ή 클래슀λ₯Ό μŠ€ν”„λ§ 빈으둜 λ“±λ‘ν•˜κ³ , 빈의 이름을 λͺ…μ‹œμ μœΌλ‘œ μ§€μ •ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜. μ΄λŠ” λ‹€λ₯Έ @Component μ–΄λ…Έν…Œμ΄μ…˜μ˜ 기반이 λ©λ‹ˆλ‹€.
β€’
Test.java
@Autowired @Qualifier("myBean") private MyBean myBean;
Java
볡사
β€’
MyBean.java
@Component("myBean") // "MyBean "μ΄λΌλŠ” μ΄λ¦„μœΌλ‘œ λΉˆμ„ λ“±λ‘ν•©λ‹ˆλ‹€. public class MyBean { // 클래슀 λ‚΄μš© }
Java
볡사

μƒμ„±μž μ£Όμž…

: 객체 생성 μ‹œμ— ν•„μš”ν•œ μ˜μ‘΄μ„±μ„ μƒμ„±μžλ₯Ό 톡해 μ£Όμž…ν•˜λŠ” 방식
일반적으둜 더 많이 μ‚¬μš©λ˜λ©°, λΆˆλ³€μ„±κ³Ό ν•„μˆ˜μ μΈ μ˜μ‘΄μ„±μ„ ν™•μ‹€ν•˜κ²Œ ν•  λ•Œ μœ μš©ν•¨.
β€’
BoardService.java
@Service public class BoardService { private BoardDAO boardDAO; @Autowired public BoardService(BoardDAO boardDAO) { this.boardDAO = boardDAO; } }
Java
볡사
β€’
BoardDAO.java
@Repository public class BoardDAO { ... }
Java
볡사

λ©”μ„œλ“œ μ£Όμž…

: 주둜 μ„Έν„° λ©”μ„œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ 빈이 μƒμ„±λœ 후에 μ˜μ‘΄μ„±μ„ μ£Όμž…ν•˜λŠ” 방식 생성 이후에 μ˜μ‘΄μ„±μ΄ 변경될 수 μžˆλŠ” κ²½μš°μ— ν™œμš©λ¨. μƒμ„±μž μ£Όμž…κ³Ό 달리 선택적인 μ˜μ‘΄μ„±μ„ μ²˜λ¦¬ν•  λ•Œ μ‚¬μš©λ  수 있음.
β€’
BoardService.java
@Service public class BoardService { private BoardDAO boardDAO; @Autowired public void setBoardDAO(BoardDAO boardDAO) { this.boardDAO = boardDAO; } }
Java
볡사
β€’
BoardDAO.java
@Repository public class BoardDAO { ... }
Java
볡사

빈 μ •μ˜ν•˜κ³  IoC μ»¨ν…Œμ΄λ„ˆμ— λ“±λ‘λœ λͺ¨λ“  빈 쑰회

ν”„λ‘œμ νŠΈ ꡬ쑰

spring-di/ β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ main/ β”‚ β”‚ β”œβ”€β”€ java/ β”‚ β”‚ β”‚ └── com/ β”‚ β”‚ β”‚ └── joeun/ β”‚ β”‚ β”‚ └── springdi/ β”‚ β”‚ β”‚ β”œβ”€β”€ bean/ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ Person.java β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ Student.java β”‚ β”‚ β”‚ β”‚ └── Test.java β”‚ β”‚ β”‚ β”œβ”€β”€ ServletInitializer.java β”‚ β”‚ β”‚ └── SpringDiApplication.java β”‚ β”œβ”€β”€ resources/ β”‚ β”‚ β”œβ”€β”€ application.properties β”‚ β”‚ β”œβ”€β”€ static/ β”‚ β”‚ └── templates/ └── build.gradle

ν”„λ‘œμ νŠΈ ν™˜κ²½

β€’
Spring boot version : 3.3.5
β€’
Group Id : com.aloha
β€’
Artifact Id : spring-di
β€’
Java version : JDK 17
β€’
Packaging : WAR
β€’
Dependency
β—¦
Spring Dev Tools
β—¦
Lombok

μž‘μ—… 파일

β€’
Person.java
β€’
Student.java
β€’
Test.java
β€’
SpringDiApplication.java

Person.java

package com.aloha.spring_di.bean; import org.springframework.stereotype.Component; import lombok.Data; @Data @Component("person") // 이 클래슀λ₯Ό μŠ€ν”„λ§ 빈으둜 λ“±λ‘ν•˜κΈ° μœ„ν•œ μ–΄λ…Έν…Œμ΄μ…˜ public class Person { private String name; private int age; // κΈ°λ³Έ μƒμ„±μž public Person() { this.name = "김쑰은"; this.age = 20; } }
Java
볡사

Student.java

package com.aloha.spring_di.bean; import org.springframework.stereotype.Component; import lombok.Data; @Data @Component("student") public class Student extends Person { private int studentId; private String grade; public Student() { super(); this.studentId = 1001; this.grade = "1"; } @Override public String toString() { return "Student{name='" + getName() + "', age=" + getAge() + ", studentId=" + studentId + ", grade='" + grade + "'}"; } }
Java
볡사

Test.java

package com.aloha.spring_di.bean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class Test { @Autowired private Person person; @Autowired private Student student; public void print() { System.out.println("person : " + person); System.out.println("student : " + student); } }
Java
볡사

SpringDiApplication.java

package com.aloha.spring_di; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import com.aloha.spring_di.bean.Test; // alt + shift + O : 전체 import @SpringBootApplication public class SpringDiApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(SpringDiApplication.class, args); // IoC μ»¨ν…Œμ΄λ„ˆμ— λ“±λ‘λœ λͺ¨λ“  빈의 이름 쑰회 String[] allBeanNames = context.getBeanDefinitionNames(); // 쑰회된 빈 이름 좜λ ₯ for (String beanName : allBeanNames) { System.out.println("빈 이름: " + beanName); } // getBean() : 빈 μ΄λ¦„μœΌλ‘œ 빈 객체λ₯Ό κ°€μ Έμ˜΄ Test test = context.getBean(Test.class); test.print(); } }
Java
볡사

μ‹€ν–‰ κ²°κ³Ό

Github (μ†ŒμŠ€μ½”λ“œ)