[Spring] Spring - DI

Fortice·2021년 1월 2일
1

Spring

목록 보기
1/13
post-thumbnail

Spring

스프링은 기업처럼 대규모 요청을 처리하는 자바 엔터프라이즈 기술을 상요하는 서버 환경을 위해 만들어졌다. 따라서 기술을 이해할 때 이 환경을 이해하고 시작해야한다.

어느정도 공부를 해보니, 기본적으로 SOLID의 규칙을 기본적으로 따르다 보니 특정 형태가 나오고, 이를 따르는 기본 개념을 통해 발전해나간 것 같다. 디자인 패턴이나 SOLID같은 규칙을 알아둘 필요가 있다.

오늘의 주제는 DI이다. DI를 이해하기 위해 스프링을 알아야하고, 그 전에 스프링의 대표 개념인 IoC, 동작 방식이라 할 수 있는 싱글톤을 알아야한다.

IoC

IoC - 제어의 역전(Inversion of Control

일반적인 제어의 흐름은 오브젝트에서 다른 "정해진" 오브젝트를 생성, 호출하고 그 오브젝트의 흐름을 따른다. 이미 정해진 클래스를 해당 오브젝트에서 알고 생성하는 것이다. 하지만 IoC를 따르면 오브젝트가 이런 정해진 오브젝트를 생성하지 않고, 사실 정해지지도 않는다. 이 말은 제어를 오브젝트 본인이 주도하는게 아니라, 다른 과정에 맡긴다는 것이다.

이 과정은 실행되는 시점에 사용자에 의해 정해질 것이다. 이렇게 되려면 클래스 내에서 new를 통해 정해진 오브젝트를 생성하던 방식에서 오브젝트 생성자에 파라미터를 넘겨 런타임에 사용자가 정하게 하면 된다.

의존적인 코드

public class UserDao {
    private ConnectionMaker connectionMaker;
    public UserDao() {
        connectionMaker = new myConnection();
    }
    public void add(User user) throws ClassNotFoundException, SQLException {
        Connection c = connectionMaker.makeConnection();
    }
}

IoC 코드

public class UserDao {
    private ConnectionMaker connectionMaker;
    public UserDao(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
    }
}
public static void main( String[] args ) throws ClassNotFoundException, SQLException 
    {
    	ConnectionMaker connectionMaker = new myConnection();
        UserDao dao = new UserDao(connectionMaker);
    }

이런 정해진 클래스에 따른 클래스 변경 시 유지 보수, 새로운 기능에 대한 변경에 좀 자유로울 수 있다.

스프링 IoC

스프링 IoC 용어에 대해 알아보자.

  • 스프링이 IoC 방식으로 관리하는 오브젝트이다. 모든 오브젝트가 빈은 아님에 주의해야한다.

  • 빈 팩토리

    스프링의 IoC를 담당하는 핵심 컨테이너이다. 빈을 등록, 생성, 조회 하는 등 빈을 관리하는 기능을 담당한다. 단순히 빈을 관리하는 측면에서의 용어다.

  • 애플리케이션 컨텍스트

    빈 팩토리에서 스프링의 부가적인 기능이 추가된 것이라 보면 되고, 스프링의 기능에 대해 초점이 맞춰져 있다고 생각하면 된다. BeanFactory를 상속한다.

위의 UserDao같은 오브젝트를 빈이라고 보면되고, 이를 관리하는 main이 현재 빈 팩토리 이다. 스프링에서는 이를 어노테이션으로 나타내어 관리할 수 있다. 어노테이션을 통해 오브젝트에 대한 설정정보를 담고있는 것으로 나타낼 수 있다. 빈은 @Bean을 붙여주고, 현재는 main에서 관리하도록 만들었지만 이를 위한 팩토리 클래스를 하나 만들고 이를 빈 팩토리라고 하면 @Configure를 통해 이를 알린다.

public static void main(String[] args) {
	ApplicationContext context = new AnnotationConfigApplicationContext([팩토리 명].class);
    UserDao dao = context.getBean("[팩토리 안 빈 이름]", [빈 클래스명].class)

main에서 위의 코드처럼 호출할 수 있다.

싱글톤

스프링은 싱글톤으로 돌아간다. 싱글톤은 간단히 말해서, 동작중에 오브젝트를 여러개 생성하지 않고, 하나 혹은 소수를 공유해 사용하는 것이다. 이는 맨 처음 말했던 대규모 요청이 들어오는 환경이기에, 요청마다 new를 통해 새로운 객체를 생성할 수 없어서이다.

위의 코드를 보면 보통 new를 통해 생성하던 오브젝트를, getBean을 통해 불러오는 방식으로 바꾸었다. 이렇게 하면 new와는 다르게 싱글톤 객체가 생성된다.

new를 통해 똑같은 클래스의 객체를 생성하면 둘은 동일한 값을 가지나, 같은 오브젝트는 아니다. 하지만 싱글톤은 같은 오브젝트이며 공유한다.

자바에서의 싱글톤 패턴은 private 생성자나, 싱글톤을 보장하는 개발을 해야하는 등 제약적인 부분이 많다. 스프링은 이를 간단하고, 사용성도 좋게 해준다.

다만 싱글톤에 따라 메모리를 공유하기 때문에 인스턴스 변수들에 대한 설계를 잘 고려해야한다.

DI (Dependency Injection)

DI를 알기 전에 먼저 의존관계에 대해 알아보자

public UserDao() {
        connectionMaker = new myConnection();
}

위 코드에서 UserDao는 myConnection을 직접적으로 불러 사용한다. myConnection의 내용이 변경, 추가됨에 따라 UserDao가 영향을 받을 수 있다. 하지만 myConnection은 UserDao가 어떻게 되든 상관 없다. 이것을 UserDao가 myConnection에 의존한다고 하며, 둘은 의존관계에 있는 것이다.

우리는 인터페이스를 만들고, 생성자 파라미터로 myConnection을 넣어주도록 변경하여, UserDao는 인터페이스에만 의존하게 되어 myConnection이 변경되어도 인터페이스만 따르면 문제가 없도록 의존이 약해졌다.

위처럼 런타임 시에 의존 관계를 맺는 myConnection 같은 오브젝트르 의존 오브젝트라 부른다.

DI를 다시 설명하면 구체적인 의존 오브젝트와 그것을 사용할 주체 오브젝트(클라이언트)를 런타임 시에 연결해주는 작업을 말한다.

DI 조건

  • 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서 인터페이스에 의존해야 한다.
  • 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제 3의 존재가 결정한다.
  • 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공해줌으로써 만들어진다.

DL (Dependency Lookup)

DI 와 비슷하지만, 의존 오브젝트를 능동적으로 찾기 때문에 DL이라 부르는 것이 있다. 의존관계를 경정하는 것과, 오브젝트 생성 작업은 외부 컨테이너에게 IoC로 맡기지만, 이를 가져올 때 메소드나 생성자를 통한 주입 대신 스스로 컨테이너에게 요청하는 방식이다.

컨테이너를 DaoFactory로 만들었다고 가정하자

public UserDao(){
	DaoFactory daoFactory = new DaoFactory();
    this.connectionMaker = daoFactory.connectionMaker();
}

이렇게 자신의 컨테이너에게 요청을 해, myConnection과의 의존관계는 역시 없고, 인터페이스와의 의존만 생긴다.

이는 DI보다 어색해 보이지만, 검색하는 오브젝트는 자신이 스프링의 빈일 필요가 없다는 장접이 있다.
UserDao는 빈일 필요 없고 ConnectionMaker만 빈이면 된다.

장점

이런 기술을 사용할 때 어떤 개선점이 있는지가 중요할 것이다.
간단히 하면 객체지향 설계와 프로그래밍의 원칙을 따랐을 때 얻을 수 있는 장점이 그대로 드러난다. (이는 추가로 공부해야겠다.)

  • 의존관계가 인터페이스에만 존재하는 구현이 어떻게 되든 상관이 없다. 즉 대상의 유지 보수, 확장이 매우 자유롭다
  • 인터페이스의 틀만 맞추면 어떤 것이든 적용할 수 있다
profile
서버 공부합니다.

0개의 댓글