1. IoC란?
- IoC(Inversion of Control)는 제어의 역전이라 하고, 객체의 생성, 생명주기의 관리까지 모든 객체에 대한 제어권이 바뀌었다는 것을 의미하는 제어의 역전
- 일반적으로 사용자가 객체를 생성하는 대신 객체의 제어를 사용자가 아닌 객체의 생성과 관리를 수행하는 컨테이너(IoC Container)에 위임하는 형태
- Spring은 Spring Container를 사용하며 객체의 생성, 초기화, 서비스, 소멸에 대한 생명주기를 관리
Inversion of Control(제어의 역전) 의미로 객체의 생성, 소멸 등 관리를 컨테이너에서 담당
일반적으로 컨테이너는 IoC 컨테이너 즉, Spring Container를 말함
2. DI란?
- DI(Dependency Injection)는 의존성 주입이라 하고, IoC 개념을 프로그래밍적으로 구현하는 방법을 의미
- 객체를 생성하는 방식이 아닌 컨테이너로부터 주입받는 방식
- 각 클래스간의 의존관계를 Bean Factory(Container)가 자동으로 주입
- Spring은 DI 방법 중 Annotation(@Autowired) 방식이 가장 일반적
- DI : Dependency Injection(의존성 주입) 의미로 객체를 생성하는 방식이 아닌 컨테이너로부터 주입받는 방식
* - 생성자, setter, 필드의 3가지 주입 방식
* - @Component 선언으로 객체를 컨테이너에 등록/관리
* - @Component는 @Controller, @Service, @Repository로 세분화
[실습] Spring IoC 실습
1️⃣ application.xml :: 설정
을 컨테이너라고 생각하면 된다.
스프링에서 사용할 클래스를 스프링에서 관리하도록 <bean> 설정
=> 스프링 컨테이너는 application.xml에서 설정
2️⃣ @Autowired
특정 클래스에서(LgTV) 다른 클래스(Speaker)의 메서드를 사용하려면 객체를 생성해주어야 하는데,
이 때 new로 X!!!
어노테이션 이용해서 주입받기 → @Autowired
자동주입이라 (" ") 이름을 따로 명시해줄 필요 없음.
3️⃣ IoCMain.java :: 사용
main에서는 Context 객체를 생성해야한다. (주입받을 곳)
▼ 전체 실습코드 ▼
package sub1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class IoCMain {
public static void main(String[] args) {
// 스프링 컨테이너 객체 생성
ApplicationContext ctx = new GenericXmlApplicationContext("application.xml");
LgTV lg = (LgTV) ctx.getBean("lg");
lg.powerOn();
lg.SoundUp();
lg.SoundDown();
lg.powerOff();
}
}
package sub1;
import org.springframework.beans.factory.annotation.Autowired;
public class LgTV {
@Autowired
private Speaker spk;
public void powerOn() {
System.out.println("LgTV powerOn...");
}
public void powerOff() {
System.out.println("LgTV powerOff...");
}
public void SoundUp() {
spk.soundUp();
}
public void SoundDown() {
spk.soundDown();
}
}
package sub1;
import org.springframework.beans.factory.annotation.Autowired;
public class SamsungTV {
@Autowired
private Speaker spk;
public void powerOn() {
System.out.println("SamsungTV powerOn...");
}
public void powerOff() {
System.out.println("SamsungTV powerOff...");
}
public void SoundUp() {
spk.soundUp();
}
public void SoundDown() {
spk.soundDown();
}
}
package sub1;
public class Speaker {
public void soundUp() {
System.out.println("Speaker soundUp...");
}
public void soundDown() {
System.out.println("Speaker soundDown...");
}
}
[실습] Spring DI 실습
1️⃣ application.xml 설정
<!-- 스프링 컨테이너 객체 탐색 -->
<context:component-scan base-package="sub2"/>
컨테이너가 패키지 내 클래스들을 스캔함
객체를 주입할 대상을 찾는 것
자동주입을 하기 위해서 선언해주어야 함.
https://docs.spring.io/spring-framework/docs/5.3.30/reference/html/core.html#spring-core
<context:annotation-config/> 를 <context:component-scan base-package="sub2"/> 로 변경
관리해야하는 클래스가 많아질수록 생성해야하는 <bean>도 늘어남.
그래서 스캔방식을 사용하는 것.
2️⃣ @Component 선언
등록할(스캔 당할) 클래스에 @Component 선언해주어야 함.
→ @Component 선언으로 객체를 컨테이너에 등록/관리
그럼 스캔해서 컨테이너에 객체 생성이 되는데, 이름은 자동으로 클래스명 소문자로 지정됨.
만약 이름을 다르게 지정하고 싶다 하면 (" ")에 네이밍을 주면 됨.
+)
그리고 마찬가지로 main에서 Context 객체를 생성해주어야 함!!
-------------
3️⃣ 주입 받는 3가지 방법
IoC를 구현하기 위한 기술적인 방식이 DI인데 세 가지 방식이 존재
① Constructor Inject (생성자 주입)
② Setter Inject
※ setter : 캡슐화된 클래스 멤버 값을 간접적으로 바꿀 수 있는 것
③ Filed Inject
4️⃣ 출력하기
- SpringContainerTest.java
package sub2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class SpringContainerTest {
public static void main(String[] args) {
ApplicationContext ctx = new GenericXmlApplicationContext("application.xml");
Computer com = (Computer) ctx.getBean("com");
com.show();
}
}
- Computer.java
주입받아서 출력
package sub2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("com")
public class Computer {
private CPU cpu;
private RAM ram;
// DI - 3) Field Inject
@Autowired
private HDD hdd;
// DI - 1) Constructor Inject(생성자 주입)
@Autowired
public Computer(CPU cpu) {
this.cpu = cpu;
}
// DI - 2) setter Inject
@Autowired
public void setRam(RAM ram) {
this.ram = ram;
}
public void show() {
cpu.show();
ram.show();
hdd.show();
}
}
package sub2;
import org.springframework.stereotype.Component;
@Component
public class CPU {
public void show() {
System.out.println("CPU : Ryzen7");
}
}
package sub2;
import org.springframework.stereotype.Component;
@Component
public class RAM {
public void show() {
System.out.println("RAM : SAMSUNG 16GB");
}
}
package sub2;
import org.springframework.stereotype.Component;
@Component
public class HDD {
public void show() {
System.out.println("HDD : WD 3TB");
}
}
〰 application.xml 전체코드
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 스프링 컨테이너 객체 탐색 -->
<context:component-scan base-package="sub2"/>
<bean id="lg" class="sub1.LgTV"></bean>
<bean id="samsung" class="sub1.SamsungTV"></bean>
<bean id="spk" class="sub1.Speaker"></bean>
</beans>