[Spring] DI
Categories: Spring
π κ°μΈμ μΈ κ³΅κ°μΌλ‘ 곡λΆλ₯Ό κΈ°λ‘νκ³ λ³΅μ΅νκΈ° μν΄ μ¬μ©νλ λΈλ‘κ·Έμ
λλ€.
μ ννμ§ μμ μ λ³΄κ° μμ μ μμΌλ μ°Έκ³ λ°λλλ€ :πΈ
[νλ¦° λ΄μ©μ λκΈλ‘ λ¨κ²¨μ£Όμλ©΄ 볡λ°μΌμ€κ±°μμ]
Spring Framework λͺ¨λ κ΅¬μ± - μν€ν μ²
- μ²μ¬μ§
- κΈ°μ‘΄μ νλ§ μμλ€λ©΄ μ΄λ€ 컨μ μΌλ‘ μλΉμ€λ₯Ό κ°κ³ μλμ§ μ μΆκ°λ₯ν κ².
μμ€ν μν€ν μ²
- μΈνλΌ μν€ν μ²λΌκ³ λ ν¨
- νλμ¨μ΄μ μννΈμ¨μ΄λ₯Ό λͺ¨λ ν¬ν¨νλ μ΄λ€ μμ€ν μ μ 체μ μΈ κ΅¬μ±μ ν° κ·Έλ¦ΌμΌλ‘ ννν κ²
- 컨μ λ§ λ³Ό μ μλλ‘ κ°λ¨νκ² λ¬΄μμ λͺ©μ μΌλ‘ μΈνλΌλ₯Ό ꡬμΆνλμ§ λ³΄κ³ μ μ μλ κ²
μμ
-
μ±ν μλ²λ₯Ό ꡬμΆνκΈ° μν μ ν΅μ μΈ μμ€ν μν€ν μ²
- λ¬Έμ μ
- νμ₯μ΄ λΆκ°λ₯
- μ¬μ©μκ° λ§μμ§λ€λ©΄ μ κ°μ μν€ν μ²μλ λ¬Έμ κ° λ°μ
-
κ°μ ν μν€ν μ²
- μν€ν μ² μ¬μ©μμ μμ²μ λΆμ°μμΌ μ£Όλ λ‘λ λ°Έλ°μ μμμ λμ΄μ μΉμμΌ μλ²λ₯Ό μμ μ μΌλ‘ μ΄μ - λ‘λλ°Έλ°μκ° λ‘λκ° λλλ κ³³μ 보λ΄μ€. - μ¬λ¬ λμ μΉμμΌ μλ²λ‘ νμ₯μ΄ κ°λ₯νκΈ° λλ¬Έμ μ¬μ©μμ μμ²μ΄ λμ΄λλλΌλ μλ²μ λΆνλ₯Ό μ€μΌ μ μμΌλ©°, νΉμ μλ²μ μ₯μ κ° λ°μνλλΌλ μ 체 μμ€ν μ΄ μ£½λ κ²½μ°λ₯Ό λ°©μ§κ°λ₯
- 1λ² μλ²κ° λΆνκ° κ±Έλ €μ μ£½μ΄λ λ€λ₯Έλ° 보λ΄λ©΄ λ¨ - λ©μμ§ λΈλ‘컀 μμμ λμ΄μ μΉμμΌ μλ²κ° λ€μ€ μλ²λ‘ ꡬμ±μ΄ λμ΄ μλλΌλ νΉμ μ¬μ©μλ€ κ°μ λ©μμ§λ₯Ό μ£Όκ³ λ°μ μ μλ 곡μ μ±λμ μ¬μ©νλ κ²μ΄ κ°λ₯ν΄μ§.
- λ©μΈμ§λΈλ‘컀 - μν©μ 곡μ ν μ μκ² μ€μκ° μν΅μ΄ κ°λ₯νκ² ν΄μ€.
-
μ μ‘μλ ν₯μμ μν΄ κ°μ λ μν€ν μ²
- mongoDB -> λΉκ΄κ³μ± DB
- μ¬μ©μμ μμ²κ³Ό μλ²μ μλ΅μ΄ μ΄λ£¨μ΄μ§λ μ 체 μμμ κ±Έμ³μ Blocking λλ μμκ° μλλ‘ λ¦¬μ‘ν°λΈ μμ€ν μ ꡬμ±νμ¬ ν΄λΌμ΄μΈνΈμ μμ²μ λ³΄λ€ λΉ λ₯΄κ² μ²λ¦¬κ°λ₯
- μΉμμΌμ΄ νλμ Connectionκ³Ό μ°κ²°λλ κ²μ λ°ν΄ RSocketμ νλμ Connection λ΄μμ λ€μ€ μμ² μ²λ¦¬κ° κ°λ₯νκΈ° λλ¬Έμ λλμ μμ²μ μμ μ μΌλ‘ μ²λ¦¬κ°
μννΈμ¨μ΄ μν€ν μ²
λν μ¬λ‘ : Java νλ«νΌ μν€ν μ²
β
- μ ν리μΌμ΄μ
- μννΈμ¨μ΄ μ’ λ₯μ νλλ‘μ¨ μ’κ²λ λ°μ€ν¬ν±μ΄λ μ€λ§νΈν°μμ μ¬μ©νλ μμ© νλ‘κ·Έλ¨μ λ§ν¨
- λκ²λ ν΄λΌμ΄μΈνΈμ μμ²μ μ²λ¦¬νλ μλ² μ ν리μΌμ΄μ μ μλ―Έ
-
μΉ μ ν리μΌμ΄μ μ μν μν€ν μ² β μ΄κ²μ λͺ ννκ² μ μ§ν€κ³ μλ κ²μ΄ MVC
μΉ μ ν리μΌμ΄μ μ κ³μΈ΅νμΌλ‘ ννν μν€ν μ² - κ³μΈ΅ν μν€ν μ²(N-ν°μ΄)
- API κ³μΈ΅(API Layer)μ ν΄λΌμ΄μΈνΈμ μμ²μ λ°μλ€μ΄λ κ³μΈ΅
- μΌλ°μ μΌλ‘ νν κ³μΈ΅(Presentation Layer)μ΄λΌκ³ λ λΆλ¦¬κ³
- REST APIλ₯Ό μ 곡νλ μ ν리μΌμ΄μ μ κ²½μ° API κ³μΈ΅μ΄λΌκ³ νν
- μλΉμ€κ³μΈ΅(Service Layer) = λΉμ¦λμ€ κ³μΈ΅μ API κ³μΈ΅μμ μ λ¬λ°μ μμ²μ μ 무 λλ©μΈμ μꡬ μ¬νμ λ§κ² λΉμ¦λμ€μ μΌλ‘ μ²λ¦¬νλ κ³μΈ΅μ΄λ€.
- λ°μ΄ν° μ‘μΈμ€ κ³μΈ΅(Data Access Layer)μ λΉμ¦λμ€ κ³μΈ΅μμ μ²λ¦¬λ λ°μ΄ν°λ₯Ό λ°μ΄ν°λ² μ΄μ€ λ±μ λ°μ΄ν° μ μ₯μμ μ μ₯νκΈ° μν κ³μΈ΅
-
μ κ³μΈ΅μ μλμ²λΌ ꡬν κ°λ₯.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
@Controller, Rest Class User Controller{ } @SERVICE Class UserService{ } @Repository Class UserRepository{ }
- MVCλ₯Ό λΉΌκ³ κ°λ°νλ κ²½μ°λ μμ. (μΉνλμ€(=λΉλκΈ° Framework)μ¬μ©ν λ λΉΌκ³ ) μμΌλ‘ μ΄λ° ꡬ쑰λ₯Ό μ² μ νκ² λ°λΌμΌ ν¨.
- controllerλ§ κ΅¬ννλ©΄ clientμ λ°μ΄ν° μ£Όκ³ λ°μ μ μμ. = μ μμ appμ μλ
μν€ν μ²λ‘ 보λ Spring Framework λͺ¨λ(Module) ꡬμ±
- Spring Frameworkμ λͺ¨λ μν€ν μ²λ₯Ό ν΅ν΄ Springμ΄ μ΄λ€ κΈ°λ₯λ€μ μ§μνλμ§ μ μ μμ
β
λͺ¨λ(Module)μ΄λ? Javaμμλ μΌλ°μ μΌλ‘, μ§μλλ μ¬λ¬ κ°μ§ κΈ°λ₯λ€μ λͺ©μ μ λ§κ² κ·Έλ£Ήννμ¬ λ¬Άμ΄ λμ κ²
μ΄λ¬ν λͺ¨λλ€μ Javaμ ν¨ν€μ§ λ¨μλ‘ λ¬Άμ¬ μμΌλ©°, μ΄ ν¨ν€μ§ μμλ κ΄λ ¨ κΈ°λ₯μ μ 곡νκΈ° μν ν΄λμ€λ€μ΄ ν¬ν¨λμ΄ μμ.
μΌλ°μ μΌλ‘ λͺ¨λμ μ¬μ¬μ© κ°λ₯νλλ‘ λΌμ΄λΈλ¬λ¦¬ ννλ‘ μ 곡λλ κ²½μ°κ° λ§μ.
DI
DI(Dependency Injection) -μ½λλ‘ μ΄ν΄νκΈ°
DI λ°©λ² -3κ°μ§
- μμ±μ
- μμ±μλ₯Ό ν΅ν΄ κ°μ²΄μ μ°Έμ‘°κ°μ΄ μ£Όμ - 곡μλ¬Έμμμ κΆμ₯νλ λ°©λ²
- Setter λ©μλλ₯Ό ν΅ν μ£Όμ
- νλμ μ§μ μ£Όμ - 곡μλ¬Έμμμλ μ¬λΌμ§
μμ
-
kiosk ν΄λμ€
1 2 3 4 5 6 7
public class KioskApplication implements CommandLineRunner { private Kiosk kiosk; @Autowired public KioskApplication(Kiosk kiosk) { this.kiosk = kiosk; } }
-
kioskApplication ν΄λμ€
1 2 3 4 5 6 7 8 9 10 11
public class Kiosk { private MenuItem[] menuItemArray; private Printer printer; private DiscountPolicy discountPolicy; @Autowired public Kiosk(MenuItem[] menuItemArray, Printer printer, DiscountPolicy discountPolicy) { this.menuItemArray = menuItemArray; this.printer = printer; this.discountPolicy = discountPolicy; }
- 1λ²κ³Ό 2λ²μ 곡ν΅μ
- μΈλΆλ‘λΆν° νΉμ ν κ°μ²΄λ₯Ό μ£Όμ λ°μ this ν€μλλ₯Ό μ¬μ©νμ¬ λ΄λΆνλμ ν λΉνμ¬ κ°μ μ¬μ©
- λͺ¨λ μμ±μλ₯Ό ν΅ν΄ κ°μ²΄λ₯Ό μ£Όμ
λ°μ(DI)
- KioskApplication : kioskμ μμ‘΄
- kiosk : MenuItem, Printer, discountPolicyμ μμ‘΄
- μ κ·Όμ μ΄μ private
- μΊ‘μν β λ΄λΆμμ μ¬μ©λλ λ°μ΄ν°λ€μ΄ κ°λ°μμ μ€μ λλ μ΄λ€ μμΈμ ν΅ν΄ μμλ‘ λ³κ²½λμ§ μλλ‘ λ³΄νΈνκ³ μΈλΆλ‘μ λ ΈμΆμ λ°©μ§νκΈ° μν κ²
-
private final
- final
-
λ νΌλ°μ€ νμ μΌ λ μ£Όμ κ° λ³κ²½ λΆκ°λ₯ν΄μ§ β κ°μ λμ΄μ λͺ»λ°κΏ, μμμλ μ κ·Ό λ° λ³κ²½ κ°λ₯
- μμ±μ μ£Όμμ²λ¦¬ νμ λ λΉ¨κ° μ€ λ¨λ μ΄μ = μ΄κΈ°νκ° λμ§ μμκΈ° λλ¬Έ β 무쑰건 μ΄κΈ°νκ° λμ΄μΌ ν¨.
- final μ΄ λΆκ³ μμ±μλ₯Ό λ§λ€λ©΄ NPAλ₯Ό λ°©μ§ν μ μμ
- μ΄κΈ°νλ₯Ό ν΅ν΄ Null κ°μ΄ λ€μ΄μ¬ μΌμ΄ μ μκΈ°κ² νκΈ° μν΄ β NPAλ₯Ό νΌνκΈ° μν κ°μ₯ κΈ°λ³Έμ μΈ ν¨ν΄
-
- final
-
AppConfig ν΄λμ€ β DIλ₯Ό ν΅ν΄ λ³κ²½κ³Ό νμ₯μ μ μ°ν μ½λλ₯Ό μ€κ³
1 2 3 4 5
@Bean public DiscountPolicy discountPolicy() { return new FixedAmountDiscountPolicy(100); // ν μΈ κΈμ‘μ μ¬κΈ°μ μ€μ }
- DiscountPolicy ν΄λμ€μ μμ±μλ κ°μ²΄κ° μ΅μ΄μ μμ±λ λ, κ°κ° μ λ₯ ν μΈ(FixedRateDiscountPolicy)κ³Ό μ μ‘ ν μΈ(FixedAmountDiscountPolicy)μ΄ μ μ©λ μ μλλ‘ κ°μ²΄λ€ κ° μμ‘΄ κ΄κ³λ₯Ό ꡬμ±νλ μν μ μν
-
ν μΈ μ μ± μ λ³κ²½νκ³ μΆμ λ returnκ°μ κ°μ²΄λ§ λ³κ²½ν΄μ£Όλ©΄ λ¨.
1 2 3 4 5 6 7 8 9
@Configuration public class AppConfig { @Bean public DiscountPolicy discountPolicy() { return new **FixedRateDiscountPolicy(20);** } --- μλ΅ --- }
- @bean, @configuration
- @Bean μ μ€νλ§ μ»¨ν μ΄λμμ κ΄λ¦¬ν λΉμ μ μ
@Configuration
κ°μ²΄κ° Bean μ μμ μμ€μμ λνλ΄λ ν΄λμ€ μμ€ μ£Όμ, μ€νλ§ μ»¨ν μ΄λκ° κ΄λ¦¬ν λΉμ μ μνλ ν΄λμ€μμ λͺ μνλ λ° μ¬μ©λ¨-
λ§μ½ discountPolicyκ° 2κ°κ° μλλ°
1 2 3 4 5 6 7 8 9 10
@Bean public DiscountPolicy discountPolicy(){ return new FixedAmountDiscountPolicy(100); //1. ν μΈκΈμ‘μ μ¬κΈ°μ μ€μ } @Bean public DiscountPolicy discountPolicy2(){ return new FixedRateDiscountPolicy(0.2); // 2. ν μΈλ₯ μ μ¬κΈ°μ μ€μ }
μλ ν€μ€μ€ν¬λ₯Ό μ€ννκ² λλ©΄ λ μ€μ μ΄λ€ ν μΈ μ μ± μ΄ λ°νλ κΉ?
β
- 1λ² ν μΈκΈμ‘μ μ€μ ν FixedAmountDiscountPolicyκ° λ°νλ¨
- μ΄μ λ @beanμ μ€νλ§ μ»¨ν μ΄λμ λ£μ λ λ°ννλ κ°μ²΄μ λ©μλ μ΄λ¦μΌλ‘ λ€μ΄κ°κ² λκ³ νΈμΆν κ²½μ° κ°μ²΄μ μ΄λ¦ λ¨Όμ νμΈ ν λ³μλͺ νμΈ β λκ°μ μ΄λ¦μ κ°μ§ ν μΈκΈμ‘μΌλ‘ μ€μ ν΄μ€ λ©μλκ° λ°μλ¨.
μ€νλ§ μ»¨ν μ΄λμ λΉ
λΉ; μ€νλ§ μ»¨ν μ΄λκ° κ΄λ¦¬νλ μλ° κ°μ²΄λ₯Ό μ€νλ§ λΉ(Bean), μ€νλ§ μ»¨ν μ΄λλ λ©ν μ 보λ₯Ό κΈ°λ°μΌλ‘ μ€νλ§ λΉ μμ± ν¨.
μ€νλ§ μ»¨ν μ΄λμ μμ±
ApplicationContext μΈν°νμ΄μ€λ₯Ό μΌλ°μ μΌλ‘ μ€νλ§ μ»¨ν μ΄λλΌ ν¨.
- BeanFactory
-
μ€νλ§ μ»¨ν μ΄λμ μ΅μμ μΈν°νμ΄μ€λ‘ μ€νλ§ λΉμ κ΄λ¦¬νκ³ μ‘°ννλ μν μ λ΄λΉ - getBean() λ©μλ μ 곡 주체
β¨β¨β¨β¨β¨β¨β¨β¨β¨β¨β¨β¨β¨β¨
-
-
ApplicationContext μΈν°νμ΄μ€
- ApplicationContextλ BeanFactoryλ‘ λΆν° νμ₯λ μΈν°νμ΄μ€ λΏλ§ μλλΌ EnvironmentCapable, MessageSource, ApplicationEventPublisher, ResourcePatternResolver λ± λ€μν κΈ°λ₯μ μΈν°νμ΄μ€λ€μ μμ λ°μ μ¬μ© (μΈν°νμ΄μ€λ λ€μ€ μμμ΄ κ°λ₯, μ λ€ μ λΆλ€ μΈν°νμ΄μ€ μμ μ μ μμ)
- μ΄λ¬ν μΈν°νμ΄μ€λ€μ νκ²½ λ³μ μ€μ , λ©μμ§ κ΅μ ν κΈ°λ₯, μ΄λ²€νΈ λ°μ, 리μμ€ μ‘°ν λ± λ€μν κΈ°λ₯λ€μ μ§μ
- μ¦, ApplicationContextλ λΉμ κ΄λ¦¬νκ³ μ‘°ννλ κΈ°λ₯ λΏ μλλΌ μΉ μ ν리μΌμ΄μ μ κ°λ°νλ λ° νμν λ€μν λΆκ° κΈ°λ₯λ€μ ν¨κ» μ 곡
μ€νλ§ μ»¨ν μ΄λλ μ°λ¦¬κ° νλ κ²μ²λΌ μ λν μ΄μ κΈ°λ° μλ° μ€μ ν΄λμ€λ‘λ λ§λ€ μ μμ§λ§, XML(Extensible Markup Language)λ₯Ό κΈ°λ°μΌλ‘ μμ±νλ κ²λ κ°λ₯ XMLμ λ°μ΄ν°λ₯Ό μ μνλ κ·μΉμ μ 곡νλ λ§ν¬μ μΈμ΄λ‘μ, μ»΄ν¨ν° μμ€ν κ°μ 곡μ κ°λ₯ν λ°©μμΌλ‘ λ°μ΄ν°λ₯Ό μ μνκ³ μ μ₯ν μ μμ
- AnnotationConfigApplicationContext
- κ·Έ ꡬν κ°μ²΄μ΄λ©° λ§€κ°λ³μλ‘ κ΅¬μ± μ 보(AppConfig.class)λ₯Ό λκ²¨μ£Όκ³ μμ.
μ€νλ§ μ»¨ν μ΄λμ λΉ
- μ€νλ§ μ»¨ν μ΄λλ μ΄λ κ² λ겨λ°μ κ΅¬μ± μ 보λ₯Ό κ°μ§κ³ λ©μλλ€μ νΈμΆνμ¬ λΉμ μμ±νκ³ , λΉλ€ κ°μ μμ‘΄ κ΄κ³λ₯Ό μ€μ
- λΉμ μμ±νλ κ³Όμ μμ, μ€νλ§ μ»¨ν
μ΄λλ νΈμΆλλ λ©μλμ μ΄λ¦μ κΈ°μ€μΌλ‘ λΉμ μ΄λ¦μ λ±λ‘
- μλ₯Όλ€μ΄ discountPolicy() λ©μλμ νΈμΆκ²°κ³Όλ‘
- λ°νλ new FixedAmountDiscountPolicy(100) κ°μ²΄ λΉμ
-
discountPolicy λΌλ μ΄λ¦μΌλ‘ μ€νλ§μ»¨ν μ΄λμ μ μ₯λ¨.
1 2 3 4 5 6 7
@Configuration public class AppConfig { @Bean public DiscountPolicy discountPolicy() { return new FixedAmountDiscountPolicy(100); // ν μΈ κΈμ‘μ μ¬κΈ°μ μ€μ }
- λΉ μ΄λ¦ μ€μ κ³Ό μ‘°ν
-
μ€μ : @Bean(name=β~β)
1 2 3 4 5 6 7 8
@Configuration public class AppConfig { @Bean(name="discountPolicy2") public DiscountPolicy discountPolicy() { return new FixedAmountDiscountPolicy(100); // ν μΈ κΈμ‘μ μ¬κΈ°μ μ€μ }
- λ§μ½ μμ κ°μ λ°©μμΌλ‘ λΉμ μ΄λ¦μ λ±λ‘ν΄ μ€ μ, κ°μ μ΄λ¦μ λΉμ΄ λ±λ‘λλ κ²½μ° μλ¬μ μμΈμ΄ λλ―λ‘, νμ λ€λ₯Έ μ΄λ¦μ λΉμ μμ±νλλ‘ μ£Όμ
-
μ‘°ν
-
λΉμ ν΄λμ€μ λ±λ‘ μ 보, getter/setter λ©μλλ₯Ό ν¬ν¨νλ©°, μμ λ³Έ κ²μ²λΌ κ΅¬μ± μ 보(μ€μ λ©ν μ 보)λ₯Ό ν΅ν΄ μμ±
- μ°λ¦¬κ° λκΈ΄ κ΅¬μ± μ 보λ₯Ό ν λλ‘ μ€νλ§ μ»¨ν
μ΄λκ° λΉμ μμ±νκ³ μμ‘΄ κ΄κ³λ₯Ό μ°κ²°ν΄ μ£Όλ©΄ μ΄μ μ€νλ§ μ»¨ν
μ΄λμ κ΄λ¦¬ νμ μλ κ°μ²΄ λΉλ€μ μλμ κ°μ΄
getBean()
λ©μλλ‘ μ‘°νκ°λ₯ -
getBean(λΉ μ΄λ¦, νμ ) λλ getBean(νμ )
1 2 3 4 5 6
DiscountPolicy discountPolicy = applicationContext.getBean("discountPolicy", DiscountPolicy.class); λλ = applicationContext.getBean(DiscountPolicy.class);
- getBean(νμ )μΌλ‘ bean μ‘°νμ κ°μ νμ μ κ°μ²΄κ° λ κ° μ΄μ μλ κ²½μ° μ€λ₯ λ°μ
-
-
- Main μ€ν ν΄λμ€
-
λͺ¨λ λΉ μ‘°ν
1 2 3 4 5 6 7 8 9 10 11 12 13 14
public class Main { public static void main(String[] args) { // (2) λͺ¨λ λΉ μ‘°ν ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { Object bean = applicationContext.getBean(beanDefinitionName); System.out.println("beanName=" + beanDefinitionName + " object=" + bean); } }
getBeanDefinitionNames()
λ©μλ μ¬μ©μ μ€νλ§μ»¨ν μ΄λκ° κ΄λ¦¬νλ λͺ¨λ λΉ μ‘°ν κ°λ₯
-
λΉ λ©ν μ 보 μ‘°ν
1 2 3 4 5 6 7 8 9 10 11 12 13 14
public class Main { public static void main(String[] args) { // (2) λΉ λ©νμ 보 μ‘°ν AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanDefinitionName); System.out.println("Bean name: " + beanDefinitionName + ", Scope: " + beanDefinition.getScope()); } }
-
ν μ€νΈ μΌμ΄μ€ μμ± κΈ°μ΄
- λ¨μν
μ€νΈ
- μμ λ¨μμ μ΄λ€ νΉμ ν κΈ°λ₯μ ν μ€νΈνκ³ , κ²μ¦νκΈ° μν λꡬλ₯Ό μλ―Έ
- = ν μ€νΈ μΌμ΄μ€(Test Case)λ₯Ό μμ±νλ€κ³ λ νν
- μ λ ₯ λ°μ΄ν°, μ€ν 쑰건, κ·Έλ¦¬κ³ κΈ°λ κ²°κ³Όμ λν κ°μ΄ ν¬ν¨
- μ€νλ§μμ JUnitμ΄λΌλ μ€ν μμ€ ν
μ€νΈ νλ μμν¬λ₯Ό μ 곡
- κ°κ°μ λ¨μ ν μ€νΈλ λ©μλ λ¨μλ‘ μμ±
- JUnit
test
λλ ν 리 μμμ μμ±λλ κ²μ μμΉ- ν μ€νΈ ν΄λμ€λ κ΄λ‘μ μΌλ‘ ν μ€νΈμ λμμ΄ λλ ν΄λμ€μ μ΄λ¦μ Testλ₯Ό λΆμ¬ ν΄λμ€λ₯Ό μμ±
-
기본ꡬ쑰- κ° κ²μ¦νκ³ μ νλ κΈ°λ₯ λ¨μμ λ°λΌ λ©μλλ‘ μμ±
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
import org.junit.jupiter.api.Test; public class JunitDefaultStructure { @Test public void test1() { // ν μ€νΈνκ³ μ νλ λμμ λν ν μ€νΈ λ‘μ§ μμ± } @Test public void test2() { // ν μ€νΈνκ³ μ νλ λμμ λν ν μ€νΈ λ‘μ§ μμ± } @Test public void test3() { // ν μ€νΈνκ³ μ νλ λμμ λν ν μ€νΈ λ‘μ§ μμ± } }
ν μ€νΈ λ‘μ§ μμ±
-
μμ -MainTest ν΄λμ€ - λΉ μ‘°ν λ¨μ ν μ€νΈ μμ±
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
package com.springboot.v2; import com.springboot.v2.discount.DiscountPolicy; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import static org.junit.jupiter.api.Assertions.*; class KioskApplicationTest { // μ€νλ§ μ»¨ν μ΄λ μμ± AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); // λΉ μ‘°ν ν μ€νΈμΌμ΄μ€ @Test void findBean() { // (1) given => μ΄κΈ°ν λλ ν μ€νΈμ νμν μ λ ₯ λ°μ΄ν° AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); // (2) when => ν μ€νΈ ν λμ DiscountPolicy discountPolicy = applicationContext.getBean("discountPolicy", DiscountPolicy.class); // (3) then => κ²μ¦ Assertions.assertThat(discountPolicy).isInstanceOf(DiscountPolicy.class); } }
-
ν μ€νΈ μ€ν
-
μΆλ ₯
-
λΉμ¦λμ€ λ‘μ§
given - when - then
μ BDD(Behavior Driven Development)λΌκ³ λΆλ₯΄λ ν μ€νΈ λ°©μμμ μ¬μ©λλ λ°©λ²
(1) given: μ λ ₯ λ°μ΄ν°
- ν μ€νΈμ νμν μ΄κΈ°ν κ° λλ μ λ ₯ λ°μ΄ν°λ₯Ό μλ―Έ
- μμ μμ μ κ²½μ°, λΉ μ‘°ν ν μ€νΈμ νμν μ΄κΈ°ν μΈν μ AppConfigurer ν΄λμ€λ₯Ό κ΅¬μ± μ λ³΄λ‘ νλ μ€νλ§ μ»¨ν μ΄λλ₯Ό μμ±νλ κ²
(2) when: μ€ν λμ
- ν μ€νΈν μ€ν λμμ μ§μ .
- λΉ μ‘°ν ν
μ€νΈμμ μ€νν λμμ
getBean()
λ©μλλ₯Ό μ¬μ©νμ¬ λΉμ λΆλ¬μ€λ κ²
(3) then: κ²°κ³Ό κ²μ¦
- ν μ€νΈμ κ²°κ³Όλ₯Ό μ΅μ’ μ μΌλ‘ κ²μ¦νλ λ¨κ³
- μΌλ°μ μΌλ‘ ν
μ€νΈ κ²°κ³Ό μμλλ κΈ°λκ°(
expected
)κ³Ό μ€μ μ€ν κ²°κ³Όμ κ°μ λΉκ΅νμ¬ ν μ€νΈλ₯Ό κ²μ¦ - μ£Όλ‘ JUnit λλ AssertJ λΌμ΄λΈλ¬λ¦¬μμ μ 곡νλ Assertions ν΄λμ€μ κΈ°λ₯λ€μ νμμ λ°λΌ μ¬μ©νμ¬ κ²μ¦μ μ§νν¨
- μμ μ½λλ AssertJ λΌμ΄λΈλ¬λ¦¬μ Assertions ν΄λμ€μ λ©μλμΈ
assertThat()
μ μ¬μ©ν κ²μ¦ λ°©λ² - AssertJλ λ©μλ 체μ΄λ(method chaining)μ μ§μνκΈ° λλ¬Έμ μ€νΈλ¦Όκ³Ό μ μ¬νκ² μ¬λ¬ λ©μλλ€μ μ°μνμ¬ νΈμΆνμ¬ κ°νΈνκ² μ¬μ©μ΄ κ°λ₯
- AssertJμμ λͺ¨λ ν
μ€νΈμ½λλ
assertThat()
μ μ¬μ©νκ³ , ν μ€νΈλ₯Ό μ€νν λμμ νλΌλ―Έν°λ‘ μ λ¬νμ¬ νΈμΆ, νΈμΆμ κ²°κ³Όλ‘ObjectAssert
νμ μ μΈμ€ν΄μ€λ₯Ό λ°ννλλ°, μ΄λ₯Ό μ¬μ©νμ¬isInstanceOf()
,isSameAs()
,isNotNull()
,isNotEmpty()
λ± λ€μν κ²μ¦μ νΈλ¦¬νκ² μ€νκ°λ₯. - μ°λ¦¬κ° μμ±ν μ½λλ₯Ό ν΄μν΄ λ³΄λ©΄, λ¨Όμ
Assertions.assertThat()
λ©μλμ ν μ€νΈλ₯Ό μ€νν μ°Έμ‘°λ³μdiscountPolicy
λ₯Ό μ λ¬μΈμλ‘ μ λ¬νκ³ , λ©μλ 체μ΄λμ μ¬μ©νμ¬isInstanceOf()
λ©μλλ₯Ό μ¬μ©νκ³ μμ isInstanceOf()
λ©μλλ λμ νμ΄ μ£Όμ΄μ§ μ νμ μΈμ€ν΄μ€μΈμ§ κ²μ¦ν λμ μ¬μ©, μλ°μinstanceOf()
λ©μλμ μ μ¬νλ€κ³ ν μ μμ΅λλ€.
μ€νλ§μ»¨ν μ΄λ(=Singleton container)- μ΄ν΄μκ°
- μ€νλ§ μ»¨ν μ΄λλ μ±κΈν€ 컨ν μ΄λ μν μ μν
- μ€νλ§ μ»¨ν μ΄λλ μ±κΈν€ λ μ§μ€νΈλ¦¬ κΈ°λ₯μ κ°μ§κ³ μλ μ±κΈν€ 컨ν μ΄λμ΄κΈ° λλ¬Έμ κ·Έ μμμ μμ±λκ³ κ΄λ¦¬λλ κ°μ²΄λ€μ΄ μ±κΈν€μΌλ‘ κ΄λ¦¬λ¨
-
μ±κΈν€μΌλ‘ κ°μ²΄λ₯Ό μμ± λ° κ΄λ¦¬νλ κΈ°λ₯μ μ±κΈν€ λ μ§μ€νΈλ¦¬(Singleton Registry)
- μ±κΈν€ν¨ν΄
- νΉμ ν΄λμ€μ μΈμ€ν΄μ€κ° λ¨ νλλ§ μμ±λλλ‘ λ³΄μ₯νλ λμμΈ ν¨ν΄
- κ³ κ°μ μμ²λ§λ€ new μ°μ°μλ₯Ό μ¬μ©νμ¬ κ°μ²΄λ₯Ό μμ±νλ©΄ ν° λ©λͺ¨λ¦¬ λλΉλ₯Ό μ΄λ.
- μ±κΈν€ ν¨ν΄μ ꡬννμ¬ μ΅μ΄μ λ¨ νλμ κ°μ²΄λ₯Ό μμ±νκ³ μμ²μ΄ μμ λλ§λ€ κ°μ κ°μ²΄λ₯Ό 곡μ νλ λ°©λ²μΌλ‘ λ©λͺ¨λ¦¬ λλΉλ₯Ό μ΅μν νλ κ²μ΄ κ°λ₯.
-
μμ : μ±κΈν€μ μ μ©νμ¬ μμ±ν ν μ€νΈ μ½λ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; public class SingletonTest { // μ±κΈν€ ꡬν O @Test void runWithSingleton() { TestConfig2 testConfig2 = new TestConfig2(); // productRepository κ°μ²΄ μμ± ProductRepository productRepository = testConfig2.productRepository(); ProductRepository productRepository2 = testConfig2.productRepository(); // μμ±ν λ κ°μ κ°μ²΄κ° κ°μ μ°Έμ‘°κ°μ κ°μ§κ³ μλμ§ κ²μ¦ Assertions.assertThat(productRepository).isSameAs(productRepository2); } // ν μ€νΈλ₯Ό μν TestConfig2 ν΄λμ€ static class TestConfig2 { private final ProductRepository productRepository = new ProductRepository(); private TestConfig2(){} public ProductRepository productRepository() { return productRepository; } } }
λ¬Έμ μ
- μ±κΈν€ ν¨ν΄μ μ¬μ©νλ©΄ λ°λ³΅μ μΌλ‘ μ¬μ©λλ κ°μ²΄λ₯Ό λ§€λ² μλ‘κ² μμ±νμ§ μκ³ νλμ κ°μ²΄λ₯Ό 곡μ νμ¬ λ©λͺ¨λ¦¬ λλΉλ₯Ό μ΅μν
- μ§μνλ κ²μ΄ μ’μ β κ°μ²΄ κ° λμ κ²°ν©λκ° μΌκΈ°λκΈ° λλ¬Έ
- λν private final μ¬μ©μΌλ‘ λ³κ²½κ³Ό νμ₯μ μ΄λ €μ
λΉ μλͺ μ£ΌκΈ°μ λ²μ
μ€νλ§ μ»¨ν μ΄λλ ν¬κ² μ΄κΈ°νμ μ’ λ£λΌλ μλͺ μ£ΌκΈ°(life-cycle)λ₯Ό κ°μ§
-
λΉ κ°μ²΄ μλͺ μ£ΌκΈ°
(1) κ°μ₯ λ¨Όμ λΉ κ°μ²΄λ€μ μμ±
(2) κ°μ²΄λ€ κ° μμ‘΄ κ΄κ³λ₯Ό μ€μ
(3) μμ‘΄ κ΄κ³ μ€μ μ΄ μλ£λλ©΄ λ΄λΆμ μΌλ‘ μ§μ ν λ©μλλ₯Ό νΈμΆνμ¬ λΉ κ°μ²΄μ μ΄κΈ°νλ₯Ό μ§ν
(4) λΉ κ°μ²΄λ€μ μ¬μ©μ΄ λ§λ¬΄λ¦¬λκ³ μ€νλ§ μ»¨ν μ΄λκ° μ’ λ£λλ©΄, μ€νλ§ μ»¨ν μ΄λλ μ§μ ν λ©μλλ₯Ό νΈμΆνμ¬ λΉ κ°μ²΄λ€μ μλ©Έμ μ²λ¦¬
- μ€νλ§ μ»¨ν
μ΄λμ λΉ κ°μ²΄ μλͺ
μ£ΌκΈ° μ΄ν΄ νμμ±
-
νμν κΈ°λ₯ ꡬνμ νκΈ° μν¨
Ex) λ°μ΄ν°λ² μ΄μ€μ 컀λ₯μ ν, μ±ν ν΄λΌμ΄μΈνΈμ κΈ°λ₯ λ±μ ꡬν
- 컀λ₯μ νμ μν λΉ κ°μ²΄λ λ°μ΄ν°λ² μ΄μ€λ₯Ό μ°κ²°νλ©°, μ±ν ν΄λΌμ΄μΈνΈλ μλ²μμ μ°κ²°μ μ§ν
- λ°λλ‘, 컨ν μ΄λκ° μ’ λ£λμ΄ λΉ κ°μ²΄κ° μλ©Έλλ μμ μμλ λ°μ΄ν°λ² μ΄μ€ λλ μλ²μμ μ°κ²°μ μ μ νκ² λμ΄λΌ μ μμ΄μΌ ν¨
-
- μ€νλ§μ μμ‘΄ κ΄κ³ μ€μ μ΄ μλ£λ μμ κ³Ό μ€νλ§ μ»¨ν
μ΄λμ μ’
λ£ μ§μ μ μμ μ μ§μ λ λ©μλλ₯Ό νΈμΆνμ¬ κ°λ°μλ‘ κ°κ°μ μμ μ νμν μμ
μ μνν μ μλλ‘ μ§μ
-
InitializingBean & DisposableBean μΈν°νμ΄μ€
1 2 3 4 5 6 7 8 9
// μ΄κΈ°ν λ¨κ³μμ μ€νλλ λ©μλ public interface InitializingBean { void afterPropertiesSet() throws Exception; } // μλ©Έ λ¨κ³μμ μ€νλλ λ©μλ public interface DisposableBean { void destroy() throws Exception; }
- λΉ κ°μ²΄κ° InitialzingBeanκ³Ό DisposableBean μΈν°νμ΄μ€λ₯Ό ꡬν β μ€νλ§ μ»¨ν
μ΄λλ μ΄κΈ°ν κ³Όμ κ³Ό μλ©Έ κ³Όμ μμ κ°κ° λΉ κ°μ²΄μ
afterPropertiesSet()
λ©μλμdestroy()
λ©μλλ₯Ό μ€ν -
μμ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
public class TestClient implements InitializingBean, DisposableBean { private String url; public TestClient(String url) { System.out.println("μμ±μ νΈμΆ."); this.url = url; } @Override public void afterPropertiesSet() throws Exception { System.out.println("μ΄κΈ°ν λ©μλ μ€ν."); } public void connect() { System.out.println("ν΄λΌμ΄μΈνΈλ₯Ό " + url + "λ‘ μ°κ²°."); } @Override public void destroy() throws Exception { System.out.println("μ’ λ£ λ©μλ μ€ν."); } }
- but, λ¬Έμ μ O β μ€νλ§ μ μ© μΈν°νμ΄μ€μ΄κΈ° λλ¬Έμ, μ΄κΈ°νμ μλ©Έ λ©μλμ μ΄λ¦μ κ°λ°μκ° μμλ‘ λ³κ²½λΆκ° / μ§μ ꡬνν ν΄λμ€κ° μλ μΈλΆμμ λ°μ λΌμ΄λΈλ¬λ¦¬λ ν΄λμ€ λ±μ λ κ°μ§ μΈν°νμ΄μ€λ₯Ό μ μ©ν μ μλ λ°©λ²μ΄ μμ
- λΉ κ°μ²΄κ° InitialzingBeanκ³Ό DisposableBean μΈν°νμ΄μ€λ₯Ό ꡬν β μ€νλ§ μ»¨ν
μ΄λλ μ΄κΈ°ν κ³Όμ κ³Ό μλ©Έ κ³Όμ μμ κ°κ° λΉ κ°μ²΄μ
-
λ¬Έμ μ 보μ, μΈν°νμ΄μ€λ₯Ό ꡬννλ λΆλΆμ μμ ,
init()
κ³Όclose()
λ©μλ1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
public class TestClient { private String url; public TestClient(String url) { System.out.println("μμ±μ νΈμΆ."); this.url = url; } public void init() { System.out.println("init() μ΄κΈ°ν λ©μλ μ€ν."); } public void connect() { System.out.println("ν΄λΌμ΄μΈνΈλ₯Ό " + url + "λ‘ μ°κ²°."); } public void close() { System.out.println("close() μ’ λ£ λ©μλ μ€ν."); } } ---------------------------------------------------------------- @Configuration public class ClientConfig { @Bean(initMethod = "init", destroyMethod = "close") public TestClient testClient() { TestClient testClient = new TestClient("www.naver.com"); return testClient; } }
-
@PostConstructμ @PreDestory μ λν μ΄μ μ νμ© : μ΅μ μ€νλ§μμ κ°μ₯ κΆμ₯νλ λ°©λ²
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
public class TestClient { private String url; public TestClient(String url) { System.out.println("μμ±μ νΈμΆ."); this.url = url; } @PostConstruct public void init() { System.out.println("init() μ΄κΈ°ν λ©μλ μ€ν."); } public void connect() { System.out.println("ν΄λΌμ΄μΈνΈλ₯Ό " + url + "λ‘ μ°κ²°."); } @PreDestroy public void close() { System.out.println("close() μ’ λ£ λ©μλ μ€ν."); } }
-
- λΉ κ°μ²΄μ κ΄λ¦¬ λ²μ
- λΉ κ°μ²΄μ μ€μ½νλ μ΄λ¦ κ·Έλλ‘ λΉ κ°μ²΄κ° μ‘΄μ¬ν μ μλ λ²μλ₯Ό μλ―Έ
- μ€νλ§ μ»¨ν μ΄λ μμμ κ΄λ¦¬λλ μ€νλ§ λΉλ μ€νλ§ μ»¨ν μ΄λμ μμ±κ³Ό μ’ λ£μ ν¨κ» μ΄λͺ μ κ°μ΄ ν¨
-
λΉ κ°μ²΄μ κ΄λ¦¬ λ²μμλ μ±κΈν€ μΈμλ νλ‘ν νμ (prototype), μΈμ (session), 리νμ€νΈ(request) λ±μ λ²μκ° μ‘΄μ¬
ScopeTest ν΄λμ€
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
public class ScopeTest { @Test public void scopeTest() { // 컨ν μ΄λ μμ± AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(TestBean.class); // 컨ν μ΄λ μ¬μ© TestBean bean = annotationConfigApplicationContext.getBean(TestBean.class); TestBean bean2 = annotationConfigApplicationContext.getBean(TestBean.class); System.out.println("bean = " + bean); System.out.println("bean2 = " + bean2); // κ²μ¦ Assertions.assertThat(bean).isSameAs(bean2); // 컨ν μ΄λ μ’ λ£ annotationConfigApplicationContext.close(); } static class TestBean { // μ΄κΈ°ν λ©μλ μ€μ @PostConstruct public void init() { System.out.println("init() μ΄κΈ°ν λ©μλ μ€ν."); } // μ’ λ£ λ©μλ μ€μ @PreDestroy public void close() { System.out.println("close() μ’ λ£ λ©μλ μ€ν."); } } }
- prototypeμΌλ‘ κ²μ¬νκ³ μΆμΌλ©΄ TestBean ν΄λμ€ μμ
@Scope("prototype")
μ λν μ΄μ λΆμ΄λ©΄ λ¨.
- prototypeμΌλ‘ κ²μ¬νκ³ μΆμΌλ©΄ TestBean ν΄λμ€ μμ
μ»΄ν¬λνΈ μ€μΊκ³Ό μμ‘΄μ± μλ μ£Όμ
- @Configurationκ³Ό @Beanμ μ¬μ©ν μλ μ£Όμ
λ°©μ
- λΉμ μκ° λ§μ κ²½μ° λ²κ±°λ‘μ.
- μ»΄ν¬λνΈ μ€μΊ @ComponentScan
- μλμΌλ‘ μ€νλ§ λΉμ λ±λ‘νλ κΈ°λ₯, ꡬ체μ μΈ μμ‘΄ κ΄κ³ μ€μ μ΄ λΆκ°λ₯
- λ²μ λ³κ²½νκ³ μΆμΌλ©΄ @ComponentScan(basePackages = ββ) μμ ββ λΆλΆμ ν¨ν€μ§ μ΄λ¦μ νμ
- @Configuration μ λν μ΄μ ,@Controller, @Service, @Repository λ±μ μ λν μ΄μ λ μ»΄ν¬λνΈ μ€μΊμ λμμ ν¬ν¨
- @Autowired μ λν
μ΄μ
- λΉμ μλμΌλ‘ λ±λ‘ν¨κ³Ό λμμ μμ‘΄ κ΄κ³κ° μ€μ
- μμ±μκ° λ¨ νλλ§ μ‘΄μ¬νλ κ²½μ°μλ @Autowired μ λν μ΄μ μ λΆμ΄μ§ μμλ μλμΌλ‘ μμ‘΄ κ΄κ³κ° μ°κ²°
### comment
λ무 μ΄λ ΅λ€,, singletonλΆν°λ μ΄ν΄κ° μ μκ°μ μ°ν΄μ λ€μ λ³΄κ³ λ€λ₯Έ μλ£λ μ°Ύμλ΄μΌ ν κ² κ°λ€
κ·Έλ¦¬κ³ κ°μ¬λμ λ³λ§ μμΌμκΈ΄ νλλ°β¦.μ κΈ° μ¬μ©λ μ½λλ νλ²μ λ°λΌ μ³λ³΄λκ² λ«κ²μ§? !
Leave a comment