IoC(Inversion Of Control)란?
IoC는 제어의 역전을 뜻합니다.
제어의 역전.. 제어가 역전된다.. 이게 어떤 의미일까요?
기존의 프로그램은 구현 객체가 프로그램의 제어 흐름을 조종합니다.
즉 사용자에 의해서 흐름이 제어되며 프로그램은 사용자가 만들어놓은 흐름에 따라 실행 될 뿐입니다.
IoC는 이 상태를 반전시킨 것으로 사용자에 의해 흐름이 제어되는 것이 아닌 프로그램 자체가 제어권을 갖는 것입니다.
Non - IoC Exapmle
public class Main {
public static void main(String[] args) {
MemoryMemberRepository memoryMemberRepository = new MemoryMemberRepository();
MemberService memberService = new MemberServiceImpl(memoryMemberRepository);
/**
* memberService 를 이용한 코드
*/
}
}
일반적인 형태의 코드입니다.
main문 안에서 필요한 객체들을 생성하고 사용하게 됩니다
이 경우 해당 객체들의 생명주기는 main이 시작하면서 생성되고 main이 종료되면서 삭제됩니다.
만약 사용자가 코드를 변경한다면
public class Main {
public static MemberService memberService = new MemberServiceImpl(new MemoryMemberRepository());
public static void main(String[] args) {
/**
* memberService 를 이용한 코드
*/
}
}
객체들의 생명주기는 클래스가 로드될때 생성되고 프로그램 종료시 삭제됩니다.
또한 사용자가 언제 memberService를 호출해 사용할 지 흐름을 정의할 수 있습니다.
사용자가 코드를 만드는 방식에 따라서 객체의 생명주기와 동작의 흐름이 바뀌게되며
이는 사용자가 프로그램의 제어 흐름을 조종하는 것과 같습니다.
IoC는 이러한 흐름을 역전시켜 프로그램이 자체적으로 흐름을 제어하는 것입니다.
IoC Exapmle
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memoryMemberRepository());
}
@Bean
public MemoryMemberRepository memoryMemberRepository() {
return new MemoryMemberRepository();
}
}
Spring FrameWork에서 자바 코드를 이용해 Bean을 등록하는 코드입니다.
이 코드를 통해서 MemberService , MemoryMemberRepository는 Spring Bean의 형태로 Context에 등록됩니다.
또한 Bean들의 생명주기또한 Context가 스스로 제어합니다.
사용자는 이 과정에 개입하지 않으며 모든 동작은 Spring이 정의해놓은 순서와 규칙을 통해 이루어집니다.
즉 사용자에게 제어권이있는게 아닌 프로그램 자체가 제어권을 갖고있는 것입니다.
이것을 제어권이 역전되었다 , IoC 되었다 라고 말합니다.
FrameWork없이 순수 자바코드로도 가능합니다.
@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
enum Method{
POST,GET
}
String[] value();
Method method() default Method.GET;
}
(사용자정의 어노테이션)
public void initialize(Set<Class<?>> c, ServletContext ctx) {
if (Objects.isNull(c)) {
log.info("Controller not found");
return;
}
for (Class<?> controllerClass : c) {
try {
Constructor<?> constructor = controllerClass.getConstructor();
Object controllerInstance = constructor.newInstance();
RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);
if (requestMapping != null) {
String[] values = requestMapping.value();
for (String value : values) {
String key = getKey(requestMapping.method().name(), value);
beanMap.put(key, controllerInstance);
}
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
ctx.setAttribute(CONTEXT_CONTROLLER_FACTORY_NAME, this);
}
이 코드는 Java Servlet을 이용해 WebApplication 을 구축하는 코드의 일부입니다.
(Java Servlet은 FrameWork이 아닌 순수자바)
Reflection 을 통해 RequestMapping 어노테이션을 갖고있는 클래스의 정보를 읽어와 객체를 생성한 후
Map에 넣어 관리하는 코드로 프로그램이 실행될 때 동적으로 클래스들을 읽어 관리하게 됩니다.
단위 테스트를 수행하는데 사용되는 프레임워크인 JUnit또한 실행 및 관리를 위한 생명주기를 갖습니다.
@SpringBootTest
class CoreApplicationTests {
@BeforeEach
void beforEach() {
}
@Test
void contextLoads() {
}
@AfterEach
void afterEach() {
}
}
사용자는 @BeforeEach , @Test , @AfterEach 어노테이션만 사용하면 프로그램이 알아서 테스트로 인식하고
실행시 JUnit이 이미 정의한 동작 순서와 생명주기에 따라 테스트하게 됩니다.
따라서 IoC가 됐다 = 프로그램이 자체적으로 흐름을 제어한다.
이렇게 정리할 수 있습니다.
프로그램의 자체적인 흐름이란??
- 프로그램이 컨테이너를 통해 생명주기를 관리한다.
- 동작의 순서가 프로그램이 정의한 흐름을 따른다.
(이런 흐름에 사용자가 억지로 개입할수는 있지만 일반적인 경우만 다루겠습니다.)
IoC의 이점
IoC/DI를 구현함으로 사용영역과 구성영역을 나눌 수 있습니다.
쉽게말하면 사용자는 객체의 실행에만 신경쓰고 , 객체들의 관리와 동작의 흐름은 프로그램이 하게 하는것입니다.
// 실행영역
public static void main(String[] args) {
// 사용자가 객체 사용시 new 를 이용해 찍어내지 않음 , Context에 등록된 Bean을 꺼내 사용
// 즉 객체를 사용자가 관리하는게 아님
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
// 따라서 객체자체의 실행에만 집중할 수 있음
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
}
// 여기는 구성영역 , 해당 객체들이 Bean에 등록되는 과정과 관리방법은 이미 Spring에 정의돼있음
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memoryMemberRepository());
}
@Bean
public MemoryMemberRepository memoryMemberRepository() {
return new MemoryMemberRepository();
}
}
실행하는 코드와 구성하는 코드를 분리하게 됨으로써 유지보수의 용이성과 가독성을 높여줍니다.
이런 IoC개념이 기본적으로 깔려있는 FrameWork는 사용자가 제어 해야 할 상당 부분들을 대신함으로써
개발 생산성을 크게 증가시켜줍니다.
Ex) 스프링 사용시 사용자는 객체의
의존관계를 어떻게 주입할것 인지만 설정해주면
Bean을 등록하고 관리하는 모든 과정은 스프링이 제어 함 (IoC/DI의 개념)
추가적으로 흔히 말하는 FrameWork Vs Library 의 가장 큰 차이도 IoC개념이 있냐 없냐의 차이가 가장 핵심적입니다.
아래는 추가로 읽으면 좋은 글입니다.
https://masiljangajji-coding.tistory.com/52
Dependency(의존관계)란?
Dependency(의존관계)란? 의존관계는 코드에서 두 모듈간의 연결을 의존관계라 합니다. 객체지향언어에서 두 클래스 간의 관계를 말하기도 합니다. 의존관계의 종류는 크게 4가지가 존재합니다. Dep
masiljangajji-coding.tistory.com
https://masiljangajji-coding.tistory.com/53
Dependency Injection(의존관계 주입)이란
Dependency Injection(의존관계 주입)이란? 이 글은 IoC , Dependency 의 개념을 알고있다는 전제하에 작성된 글입니다. 원활한 이해를 위해서 아래글을 읽어주세요 https://masiljangajji-coding.tistory.com/51 IoC(Inver
masiljangajji-coding.tistory.com
도움이 되셨으면 좋겠습니다.
'Spring > Spring Core' 카테고리의 다른 글
Dependency Injection(의존관계 주입)이란 (2) | 2024.01.04 |
---|---|
Dependency(의존관계)란? (2) | 2024.01.04 |