3주차 DI, IoC, POJO

9648 단어 POJOIoCdiIoC

DI, IoC, POJO
각 키워드의 의미
각 키워드를 잘 이해할 수 있는 예제

앞서 객체 지향 프로그래밍에 대해 공부를 하는 중이다.

스프링 프레임 워크에 있는 스프링 삼각형 IoC/DI, AOP, PSA
스프링 삼각형은 POJO(Plain Old Java Object)에 세 가지 유형의 진동을 줌으로써 거대한 프레임워크를 완성
**이미지 첨부 바람

7장 p.234 IoC/DI -제어의 역전/의존성 주입
스프링의 IoC(Inversion of Control / 제어의 역전)라고도 하는 DI(Dependency Injection / 의존성 주입)를 알아보기 전에 프로그래밍에서 의존성이란? 자바에서 의존성은?
->자바 의존성 관련한 것, 모르는 단어와 개념 - 클래스, 생성자, 객체, 메서드, 함수(메서드와 함수 구분) 그리고 머시기 : args 이거는 또 뭔가? 찾아보기

DI(Dependency Injection)란 스프링이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입 기능으로,
객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식이다.

DI(의존성 주입)를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아진다

스프링에서는 객체를 Bean이라고 부르며, 프로젝트가 실행될때 사용자가 Bean으로 관리하는 객체들의 생성과 소멸에 관련된 작업을 자동적으로 수행해주는데 객체가 생성되는 곳을 스프링에서는 Bean 컨테이너라고 부른다.

첫번째 방법은 A객체가 B와 C객체를 New 생성자를 통해서 직접 생성하는 방법이고,

두번째 방법은 외부에서 생성 된 객체를 setter()를 통해 사용하는 방법이다.

이러한 두번째 방식이 의존성 주입의 예시인데,
A 객체에서 B, C객체를 사용(의존)할 때 A 객체에서 직접 생성 하는 것이 아니라 외부(IOC컨테이너)에서 생성된 B, C객체를 조립(주입)시켜 setter 혹은 생성자를 통해 사용하는 방식이다.

즉, DI는 클래스 사이의 의존관계를 빈 설정 정보를 바탕으로 컨테이너가 자동적으로 연결해주는 것을 말한다. 개발자 입장에서는 제어를 담당할 필요없이 빈 설정 파일에 의존관계가 필요하다는 정보만 추가해주면 된다. 그러면 오브젝트 레퍼런스를 외부(Container)로부터 주입 받아서, 실행 시에 동적으로 의존관계가 생성된다. 결국 컨테이너가 흐름의 주체가 되어서 애플리케이션 코드에 의존관계를 주입해주는 것이다.

Ioc(Inversion of Control)
IoC(Inversion of Control)란 "제어의 역전" 이라는 의미로, 말 그대로 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다.

IoC는 제어의 역전이라고 말하며, 간단히 말해 "제어의 흐름을 바꾼다"라고 한다.

객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있게 하여 가독성 및 코드 중복, 유지 보수를 편하게 할 수 있게 한다.

기존에는 다음과 순서로 객체가 만들어지고 실행되었다.

1.객체 생성

2.의존성 객체 생성
클래스 내부에서 생성

3.의존성 객체 메소드 호출

하지만, 스프링에서는 다음과 같은 순서로 객체가 만들어지고 실행된다.

1.객체 생성

2.의존성 객체 주입
스스로가 만드는것이 아니라 제어권을 스프링에게 위임하여 스프링이 만들어놓은 객체를 주입한다.

3.의존성 객체 메소드 호출

스프링이 모든 의존성 객체를 스프링이 실행될때 다 만들어주고 필요한곳에 주입시켜줌으로써 Bean들은 싱글턴 패턴의 특징을 가지며,

제어의 흐름을 사용자가 컨트롤 하는 것이 아니라 스프링에게 맡겨 작업을 처리하게 된다.

그러면 IoC/DI가 적용되지 않은 코드와 적용된 코드 예시를 살펴보자.

package kr.co.hangbok;

public class Foo{
	private Bar bar;
    
    public Foo() {
    	bar = new SubBar();
    }
  }

위의 코드에서 IoC/DI가 적용되지 않았는데, 이 경우 Bar 인터페이스를 구현하는 구체적인 클래스의 이름(SubBar)를 애플리케이션 코드에서 바로 등장시켜 초기화한다. 이 때, 동적으로 구현 클래스를 정해주기 어렵다.

다음으로 IoC/DI가 적용된 코드 예시를 살펴보자.

//컨테이너
<beans>
	<bean id="bar" class="kr.co.hangbok.SubBar">
    <bean id="foo" class="kr.co.hangbok.Foo">
    	<property name="bar" ref="bar"/>
    </bean>
</beans>
//애플리케이션 코드
package kr.co.hangbok;

public class Foo {
	private Bar bar;
    
    public void setBar(Bar bar) {
    	this.bar = bar;
    }
}

IoC/DI가 적용될 경우, 우선 사용할 객체들을 컨테이너에 등록한다. 그리고 애플리케이션 코드에서 해당 객체를 setter 함수의 매개변수로 받아와서 실행 시 동적으로 의존관계를 설정해준다. 이 경우에는 Bar 인터페이스를 구현하는 구체적인 클래스의 이름이 애플리케이션 코드에 등장하지 않아, 동적으로 구현클래스를 정해줄 수 있게 된다.

따라서 IoC/DI를 사용하면 객체를 생성할 때에, 해당 객체가 참조하고 있는 다른 객체에 대한 종속성을 애플리케이션 코드 외부(Container)에 설정하게 함으로써 결합도(coupling)는 낮추면서 유연성과 확장성은 향상시킬 수 있다.

참조 - 결합도 https://ko.wikipedia.org/wiki/%EA%B2%B0%ED%95%A9%EB%8F%84

POJO
POJO란 Plain Old Java Object의 약자로 다른 클래스나 인터페이스를 상속/implements 받아 메서드가 추가된 클래스가 아닌 일반적으로 우리가 알고 있는 getter, setter 같이 기본적인 기능만 가진 자바 객체를 말한다.

POJO의 목적은 자바의 객체지향적인 특징을 살려 비즈니스 로직에 충실한 개발이 가능하도록 하는 것이다.

복잡한 개발의 필요조건을 충족시킬 수 있도록 POJO 기반의 프레임워크를 적절히 이용하는 것이 요구된다. 단순히 POJO 프레임워크를 사용하는 것이 아니라 그에 대한 여러 기준을 지켜야 한다.

가. 객체지향적인 설계 원칙에 충실하도록 개발
POJO는 자바 오브젝트는 객체지향 언어로서 자바 오브젝트의 특징을 잘 가져야 한다.
테스트하기 힘든 구조, 확장이나 재활용이 어려움이 있으면 안 된다.
나. 테스트가 용이
POJO 철학을 이용해 만들어진 애플리케이션은 자동화된 테스트 코드 작성이 편리해야 한다.

public class User {
    private int id;
    private String name;
    private String email;
    
    public int getId() {
    	return id;
    }
    public String getName() {
    	return name;
    }
    public String getEmail() {
    	return email;
    }
    
    public void setId(int id) {
    	this.id = id;
    }
    public void setName(String name) {
    	this.name = name;
    }
    public void setEmail(String email) {
    	this.email = email;
    }
}

위와 같은 클래스를 자바의 기본 객체라고 한다. (즉, Getter와 Setter로 구성된 가장 순수한 형태의 기본 클래스를 POJO)

자바를 이용해 비즈니스 서비스를 개발할 때 비즈니스 로직 뿐만 아니라 트랜잭션, 보안 등 로우레벨의 로직까지 작성해야하는 부담감을 없애고자 EJB(Enterprise Java Beans)를 만들게 되었다. EJB를 사용하면서 로우레벨의 로직 개발에 대한 수고를 덜 수 있었지만, 한 두가지 기능을 사용하기 위해 거대한 EJB를 상속받거나 implements 하게 되어 가벼운 서비스조차도 무겁게 만들어졌고, 다른 기능으로 대체하기 위해선 전체 코드를 수정해야 하는 문제점이 발생하였다.

JAVA의 기본 개념인 객체지향에 집중하고, 특정 클래스나 라이브러리에 종속되지 않는 POJO 구성으로 코드를 작성한다면 이런 문제점을 해결할 수 있을 것이라고 생각했다.
따라서 Spring은 POJO 방식을 기반으로 한 웹 프레임워크이고, IoC와 DI, AOP 등 Spring의 주요 기술을 활용해 POJO 기반의 구성을 이루게 되었다.

JAVA에서 POJO Class가 따르지 않아도 되는 제한 조건이 3가지가 있다.
1. 미리 정의된 클래스 extend

    public class Foo extends javax.servlet.http.HttpServlet { ...
  1. 미리 정의된인터페이스 implements
public class Bar implements javax.eib.EntityBean { ...
  1. 미리 정의된 annotation을 포함
@javax.persistence.Entity public class Baz { ...

POJO 개념을 사용하는 것과 사용하지 않는 것은?

눈에 크게 띄는 예시를 위해 스프링 프레임워크에서 JMS(자바 메시지 서비스)의 MessageListener로부터 메시지를 받는 예시를 살펴보겠다.

  1. 개념을 사용하지 않는
public class ExampleListener implements MessageListener {

  public void onMessage(Message message) {
    if (message instanceof TextMessage) {
      try {
        System.out.println(((TextMessage) message).getText());
      }
      catch (JMSException ex) {
        throw new RuntimeException(ex);
      }
    }
    else {
      throw new IllegalArgumentException("Message must be of type TextMessage");
    }
  }

}

JMS를 사용하기 위해 MessageListener 인터페이스를 상속받아야 한다.

하지만, JMS라는 특정 환경에 종속되게 되고 다른 메시징 설루션을 적용하기 어려워지고, 단순한 예제와 달리 Listener가 많은 경우, 다른 설루션으로 교체할 경우 더더욱 어려울 것이다.

  1. 개념을 사용하고 있는
@Component
public class ExampleListener {

  @JmsListener(destination = "myDestination")
  public void processOrder(String message) {
    System.out.println(message);
  }
  
}

반면, POJO 개념을 사용하고 있는 코드를 보면 어떠한 인터페이스에 종속되지 않는다.

@JmsListenr라는 어노테이션을 이용하여 JMS 서비스를 이용할 수 있고, 다른 설루션을 사용하고 싶은 경우, @RabbitListener로 바꿔주기만 하면 된다.

스프링 프레임워크는 위의 예제처럼 우리의 라이브러리와의 결합성을 줄이도록 도와준다.

출처) DI, Bean이란? https://velog.io/@gillog/Spring-DIDependency-Injection
IoC/DI가 적용된 코드, 적용되지 않은 코드
https://www.nextree.co.kr/p11247/
POJO의 기본 특성
https://velog.io/@galaxy/Spring%EC%9D%98-%EA%B8%B0%EB%B3%B8-%ED%8A%B9%EC%A7%95-POJO
wiki 백과의 plain old java object
POJO 관련(개념 및 예시 코드) : https://codedot.co.kr/5 [사심가득한 기록]

좋은 웹페이지 즐겨찾기