독서/토비의 스프링

토비의 스프링 Vol.1 1장 오브젝트와 의존관계

Debin 2022. 7. 21.
반응형

2023.02.13 복습 및 정리

실습 레포는 아래와 같습니다.

https://github.com/happysubin/book-study/tree/main/%ED%86%A0%EB%B9%84%EC%9D%98%20%EC%8A%A4%ED%94%84%EB%A7%81

 

이번 포스팅은 토비의 스프링 3.1 1장에 관한 학습 기록입니다. 

1장 도입부

자바는 객체지향 언어다. 우리가 학습하는 스프링은 자바를 기반으로 한 프레임워크다. 

자바를 기반으로 만들어진 기술, 스프링이 제일 중요하게 여기는 핵심 가치는 바로 객체지향적인 프로그래밍이다. 

그러므로 스프링은 오브젝트(객체)에 제일 관심을 많이 둔다. 오브젝트 간의 관계에 집중하며, 라이프 사이클에 집중한다. 

더 나아가서는 오브젝트 설계, 어떤 단위로 만들어지는지까지 관심을 가져야 한다.

결국 오브젝트에 관심을 가지면서 객체지향 프로그래밍을 학습하면 학습하는 과정에서 리팩토링, 디자인 패턴, 테스트 등 여러 가지 기술과 지식이 요구된다.

이번 1장에서는 스프링보다는 오브젝트에 집중하며 설계와 구현 그리고 스프링의 철학과 스프링이 무엇인지를 학습한다.

1.1 초난감 DAO

이번 파트에서는 하나의 DAO(Data Access Object)에 대해 살펴보았다.

예제 코드를 보면서 스프링 DB 1편이 떠올랐다. JDBC API를 사용하는데 흔히 말하는 좋지 않은 코드였다. 

DAO 코드를 요약해 설명하면 다음과 같다.

 

  1. DB 드라이버 등록 및 DB 연결을 위한 커넥션을 가져온다.
  2. SQL을 담은 Statement or PreparedStatement를 만들어 실행한다.
  3. 조회의 결과를 ResultSet으로 가져온다.
  4. 과정 중에 예외가 있다면 예외를 던진다.
  5. 작업 중에 생성된 ResultSet, Statement, 커넥션을 close한다.
  6. 이 작업이 놀랍게도 하나의 메서드에서 순차적으로 진행된다. 각 메서드마다 중복 코드(커넥션 열고 닫기)가 엄청나게 많다.

1.2 DAO의 분리

개발자가 객체를 설계할 때 가장 염두에 둬야할 사항은 바로 미래의 변화를 어떻게 대비할 것인가이다.

가장 좋은 대책은 변화의 폭을 최소한으로 줄여주는 것이다. 그렇다면 위에서 언급한 초난감 DAO의 경우로 생각해보자.

만약 초난감 DAO에 변경 요청이 들어온다. "사용하는 데이터베이스를 오라클에서 MySQL로 바꾸고 싶어요!"

데이터베이스 드라이버와 커넥션 코드를 수정해야하는데 이런 요구사항은 초난감 DAO에서 쉽게 반영할 수 있을까?

초난감 DAO 모든 메서드에서 드라이버를 등록하고 커넥션을 생성한다. 그렇다면 메서드가 200개 있다면 모든 메서드를 변경해야 한다.

이게 중복되는 코드에서 발생하는 무시무시함이다.

변화가 한 번에 한 가지 관심에 집중돼서 일어난다면, 우리는 한가지 관심이 한 곳에 집중되게 만들어야 한다.

즉 관심이 같은 것 끼리는 모으고, 관심이 다른 것은 분리해야 한다. 이것을 관심사의 분리라고 한다.

관심사의 분리

관심사의 분리를 객체지향 프로그래밍에 적용하면 관심이 같은 것끼리는 하나의 객체 안으로 또는 친한 객체로 모은다.

반대로 관심이 다른 것은 최대한 따로 떨어져서 서로 영향을 주지 않게 만든다.

현재 Dao의 관심사항은 다음과 같다.

 

  1. DB 커넥션을 어떻게 가져올지
  2. DB에 보낼 SQL문장을 담을 Statement를 만들고 실행하는 것
  3. 사용한 리소스(커넥션, Statement 등) 반환
  4. 물론 예외 처리도 당연히 있다. (이는 일단 생략)

메서드 추출 기법

현재 앞에서 언급한 것처럼 데이터베이스 커넥션을 가져오는 코드가 모든 메서드에서 중복된다.

만약에 수천개의 메서드가 있다고 생각해보자. 커넥션을 가져오는 부분에 변경 요청이 들어오면 수천개의 메서드를 수정해야 한다.

이런 일을 막기 위해 커넥션을 가져오는 중복된 코드를 분리해서 하나의 메서드로 만들자.

이를 메서드 추출 기법이라고 한다.

public class UserDao{
	
    private Connection getConnection(){
    // 커넥션을 가져오는 로직
    }

    public void add(User user){
    	Connection con = getConnection();
    	//유저 추가하는 로직
    }
    
    public User getUser(){
        Connection con = getConnection();
    	//유저 가져오는 로직
    }
    
    public List<User> getUsers(){
        Connection con = getConnection();
        //유저 리스트 가져오는 로직
    }

}

이제 커넥션에 대한 변경 요청이 들어오면 getConnection 메서드만 수정하면 된다.

관심의 종류에 따라 코드를 구분해놓았기 때문에 한 가지 관심에 대한 변경이 일어날 경우 그 관심이 집중되는 부분의 코드만 수정하면 된다.

관심 내용이 독립적으로 존재하므로 리팩토링도 간단해졌다.

상속을 통한 확장

우리의 DAO를 많은 사람과 회사가 사용한다고 가정해보자.

그러나 우리는  DAO 내부 코드를 공개하지도 않고 사용자가 수정할수 없게 만들었다.

만약 수많은 데이터베이스 회사가 우리의 DAO를 사용하면서 자기 데이터베이스를 연결하려고 하면 이는 어떻게 해결해야 할까?

이때 상속을 통해 문제를 해결할 수 있다.

 

  1. UserDao의 getConnection 코드를 제거하고 이를 추상 클래스로 만든다.
  2. UserDao를 상속한 회사별 DAO 서브 클래스를 만들고 추상 메서드를 오버라이딩해 각 회사 데이터베이스 커넥션을 가져오도록 구현한다.

상속을 통한 UserDao 확장 방법을 그림으로 나타내면 아래와 같다.

상속을 통한 확장

userDao를 상속한 커스텀 Dao에서는 부모 클래스의 추상 메서드인 getConnection()을 오버라이딩해 기능을 자유롭게 확장할 수 있다.

이제 UserDao에서는 어떻게 데이터를 등록하고 가져올 것인지에 대한 관심을 담당한다.

DB 연결 방법에 대한 관심사는 CustomDao1과 CustomDao2가 담당한다.

클래스 계층 구조를 통해 두 개의 관심이 독립적으로 분리되면서 변경 작업이 더욱 용이해졌다.

 

이렇게 슈퍼 클래스에 기본적인 로직의 흐름을 만들고,

그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브 클래스에서 이런 메소드를 필요에 맞게 구현하는 디자인 패턴을 템플릿 메소드 패턴이라고 한다.

또한 이렇게 서브 클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것을 팩토리 메소드 패턴이라고도 한다.

스프링에서 템플릿 메소드 패턴은 굉장히 많이 사용되며,

스프링 프레임워크에서 클래스명에 템플릿이 들어간다면 해당 클래스는 템플릿 메소드 패턴을 사용한다고 이해하면 된다.

 

템플릿 메서드 패턴 or 팩토리 메서드 패턴으로 관심사항이 다른 코드를 분리해내고,

서로 독립적으로 변경 또는 확장할 수 있도록 만드는 것은 간단하면서도 매우 효과적인 방법이다.

그러나 상속을 사용했다는 단점이 있다. 사실 이 부분을 읽으면서 "?" 물음표가 먼저 떠올랐다. "상속에 크나큰 단점이 있나..?"

책에서는 아래와 같은 단점이 있다고 밝힌다.

 

  • 만약 이미 UserDao가 다른 목적을 위해 상속을 사용하고 있다면 어쩔 것인가?
  • 자바는 다중 상속을 허용하지 않는다.
    단지 커넥션을 가져오기 위해 상속 구조로 만들어버리면 이후에 다른 목적으로 UserDao에 상속을 적용하기 힘들다.
  • 다른 문제는 상속을 통한 상하위 클래스의 관계가 매우 밀접하다는 점이다.
  • 상속을 통해 관심사를 분리하고, 필요에 따라 오버라이딩을 하게 만들었다.
    그러나 상속 관계는 여전히 두 가지 다른 관심사에 대해 긴밀한 결합을 허용한다.
  • 서브 클래스는 슈퍼 클래스의 기능을 직접 사용할 수 없다.(쿼리 실행)
    그래서 슈퍼클래스 내부의 변경이 있을 때는 모든 서브클래스를 함께 수정하거나 개발해야 할 수도 있다.
  • 반대로 그런 변화에 따른 불편을 주지 않기 위해 슈퍼클래스가 더 이상 변화하지 않도록 제약을 가해야 할지도 모른다.
  • 확장된 기능인 DB 커넥션을 생성하는 코드를 다른 DAO 클래스에 적용할 수 없다는 것도 단점이다.
  • 예를 들어 UserDao 이외에 다른 Dao 클래스(ex TeamDao)들이 만들어지면 그 Dao 에서도 getConnection() 중복 코드가 발생!

생각보다 많은 단점이 있었다. 특히 중복 코드가 다시 발생해버린다.

이런 문제를 어떻게 해결할 수 있을까?? 현재는 DB 커넥션 연결과 DAO 로직을 분리해 상하위 클래스로 분리했다.

이 두 개의 관심은 변화의 성격이 다르다. 여기서 새로운 단어가 등장했다. 변화의 성격이란 무엇인가???

변화의 성격

  • 변화의 이유와 시기, 주기 등이 다르다.
  • UserDao는 어떤 DB 전용 API를 사용할 것인지, 어떤 테이블과 매핑할 것이고,어떤 SQL을 작성할까에 대한 관심사에서
    변화가 발생한다.
  • 그러나 CustomDao들은 DB 연결 방법을 변경해야 변화가 발생한다.
  • 이것이 바로 변화의 성격이 다르다는 것이다.

변화의 성격이 달라서 상속으로 분리했는데 이는 뭔가 우리에 기대만큼 효율적이지 못하다.

아예 다른 클래스로 분리시켜버리자.

1.3 DAO의 확장

클래스 분리

데이터베이스 커넥션을 연결하는 부분과 DAO 로직을 수행하는 부분을 각자 다른 클래스로 분리했다.

쉽게 코드로 살펴보면 아래와 같다.

public class UserDao{
 
    private SimpleConnectionMaker simpleConnectionMaker; //클래스를 독립하고 멤버 변수로 가진다.
    
    public UserDao(){
        simpleConnectionMaker = new SimpleConnectionMaker(); 
    }
    
    public void add(User user){
        Connection connection = simpleConnectionMaker.makeNewConnection();
        //유저 저장 로직
    }
    
    public User get(){
    Connection connection = simpleConnectionMaker.makeNewConnection();
        //유저를 가져오는 로직
    }
}

public class SimpleConnectionMaker{
    public Connection makeNewConnection(){
        //새로운 커넥션을 가져온다.
    }
}

이제 simpleConnectionMaker 멤버 변수를 만들어 이를 계속 사용한다.

그럼 이제 우리가 저번에 해결한 문제가 발생한다. 다시 DAO 기능을 확장해 다양한 DB 커넥션을 사용할 수 없는 것이다.

예를 들어 오라클 DB 커넥션과 MySQL을 다양하게 사용할 수 없다.

왜냐하면 UserDao의 코드가 구체 클래스인 SimpleConnectionMaker에게 종속적이기 때문이다.

고정된 하나의 DB 커넥션 기술만 사용하므로, 유연한 설계가 아니다.

이 파트를 읽으면서 다음 이야기를 눈치챘다. "아 추상화를 도입하겠구나" 역시 바로 인터페이스 얘기가 나왔다.

역시 구체 클래스가 아닌 추상화에 의존하는 것이 좋다.

 

추상화, 즉 인터페이스를 사용해 DB 커넥션 기능을 확장했다.

인터페이스 도입 결과

ConnectionMaker를 구현한 클래스에서  추상 메서드인 makeConnection()을 오버라이딩해 데이터베이스 커넥션 생성 기능을 변경할 수 있다. 인터페이스를 도입하면서 결합도는 약해지고 더욱 유연한 설계가 되었다.

UserDao는 단지 인터페이스를 사용하면 된다.

어떤 인터페이스의 구체 클래스가 들어와서 어떤 커넥션이 생기는지 관심을 가질 필요가 없다.

 

이렇게 해서 인터페이스에 의존하면서 문제는 잘 해결된 것으로 보인다.

사실 멤버변수의 타입을 인터페이스로 사용하면서 추상화에 의존하는 것 같지만 실상은 그렇지 않다.

public class UserDao{

    private ConnectionMaker connectionMaker; //인터페이스 타입.
    
    public UserDao(){
        connectionMaker = new MConnectionMaker(); //이는 사실 구체 클래스를 의존하는 것이다. 
    }
}

결국 MConnectionMaker(); 즉 오브젝트를 생성하는 코드가 UserDao 남아있는 것이다.

추상화에 의존하는 것 같지만 결국 구체 클래스에 의존한다.

우리는 데이터베이스 커넥션 변경 요청이 들어오면 이 부분 코드를 계속 수정해야 한다.

결국 원점이다! 고객에게 자유로운 DB 커넥션을 제공할 수 없다. 어떻게 해결해야 할까?

바로 아래와 같은 코드면 해결이 된다.

public class UserDao{

    private ConnectionMaker connectionMaker; //인터페이스 타입.
    
    public UserDao(){
        connectionMaker = new ConnectionMaker(); //인터페이스 의존
    }
}

해결이네? 하지만 바로 이상함을 감지할 것이다. 바로 인터페이스 자체로는 인스턴스를 만들 수 없다. 

이러면 해결하는데 어떻게 해야하지..?? 아래와 코드와 같이 해결할 수 있다.

public class UserDao{

    private ConnectionMaker connectionMaker;
    
    public UserDao(ConnectionMaker connectionMaker){
        this.connectionMaker = connectionMaker;   //인터페이스 의존
    }
}

바로 다른 곳에서 의존하는 멤버 변수를 주입 받으면 된다.

UserDao와 UserDao가 사용할 ConnectionMaker의 특정 구현 클래스 사이의 관계를 설정해주는 것에 대한 관심을 분리하면 된다.

이 관심사를 분리하지 않으면 UserDao는 결고 독립적으로 확장 가능한 클래스가 될 수 없다.

 

위 코드를 보면 이제 외부에서 UserDao가 사용할 connectionMaker를 주입한다. 

이제 한 가지 가정을 하자. UserDao를 사용하는 클라이언트가 원하는 connectionMaker를 넣을 수 있다고.

그러면 UserDao와 UserDao가 사용할 ConnectionMaker의 특정 구현 클래스 사이의 관계를 설정해주는 관심은 이제 클라이언트가 가지고 있다. 드디어 고객이 자유롭게 DB 커넥션을 사용할 수 있는 구조가 완성된 것이다.

@Test
void mainTest{
    ConnectionMaker connectionMaker = new MConnectionMaker();
    UserDao dao = new UserDao(connectionMaker); //다형성을 활용 
    //테스트 로직 수행
}

클라이언트인 mainTest가 ConnectionMaker를 정한다.

이제 UserDao는 변경 없이 다양한 DB 커넥션을 사용할 수 있다. UserDao도 데이터 접근 작업에만 충실하게 된 것이다.

이렇게 인터페이스를 도입하고 클라이언트의 도움을 받는 것이 상속보다 훨씬 유연한 설계다.

이제 DB 커넥션을 변경하려면 클라이언트 부분 코드만 수정하면 된다.

초난감 DAO에서 꽤 멋있게 리팩토링을 해낸 것이다!

객체지향 기술의 여러 단어

책에서는 다음과 같은 단어를 소개했다.

  • SRP: 단일 책임 원칙이다.
  • OCP: 개방 폐쇄 원칙이다.
  • 높은 응집도와 낮은 결합도
    관심사를 분리하며 각 클래스마다 높은 응집도를 갖췄고, 인터페이스로 낮은 결합도를 갖췄다.
  • 전략 패턴
    마지막에 도입한 방식이 전략 패턴이다. 자신의 기능 맥락에서, 필요에 따라 변경이 필요한 부분(커넥션 메이커)을
    인터페이스를 통해 분리시키고, 이를 구현한 구체적인 클래스를 필요에 따라 바꿔서 사용하는 디자인 패턴이다.

모두 많이 들어본 단어다. 예전에 처음 토비의 스프링을 봤을 때는 모르는 단어가 많았는데, 이제는 아는 단어가 훨씬 많다.

책을 읽을수록 뭔가 뿌듯하다.

1.4 제어의 역전

충분히 잘 작성했지만 아직 문제가 남아있다. 바로 mainTest다.

여기서는 프로그램을 실행하며, 어떤 ConnectionMaker 구현 클래스를 사용할지 결정하는 책임을 떠맡았다.

그러나 mainTest는 정말 테스트를 실행하는 것이 책임이지 ConnectionMaker를 생성할 책임은 없다.

단일 책임 원칙에 따라 하나의 책임만 맡는게 좋다. 그러므로 이 부분은 리팩토링이 필요해보인다.

 

그럼 이제 리팩토링으로 어떤 클래스를 하나 만들겠다.

이 클래스는 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 것인데, 이런 일을 하는 오브젝트를 흔히 팩토리라고 부른다. 팩토리 역할을 맡은 클래스와 수정한 mainTest는 아래와 같다.

public class DaoFactory{
    public UserDao userDao(){
        ConnectionMaker connectionMaker = new DConnectionMaker(); //팩토리가 결정
        UserDao userDao = new UserDao(connectionMaker);
        return userDao;
    }
}

@Test
void mainTest{
    UserDao userDao = new DaoFactory().userDao();
    //테스트 로직 수행
}

이제 각자 자신이 맡은 책임에 모두 충실하다.

UserDao는 데이터 액세스 로직에 충실하고 ConnectionMaker는 데이터베이스 커넥션 연결에 충실하고 mainTest는 테스트에 충실하며 DaoFactory는 이런 애플리케이션의 오브젝트를 구성하고 그 관계를 정의하는 책임을 가지고 있다.

UserDao와 ConnectionMaker가 실질적인 로직을 담당하는 컴포넌트라면,

DaoFactory는 설정을 하는 컴포넌트다. 이렇게 설정 컴포넌트를 분리하면 자유로운 확장이 가능하다.

 

만약 다양한 설정을 해야 한다면 아래와 같이 DaoFactory 클래스를 작성하면 된다.

public class DaoFactory{
    
    public UserDao userDao(){
        return new userDao(connectionMaker());
    }
    
    public Item itemDao(){
        return new itemDao(connectionMaker());
    }
    
    public Order orderDao(){
        return new orderDao(connectionMaker());
    }
    
    public ConnectionMaker connectionMaker(){
        return new MConnectionMaker();
    }
}

이제 제어의 역전에 대한 개념을 알아보자.

일반적으로 프로그램의 흐름은 main 메서드에서 실행되며 사용할 오브젝트를 결정하고,

만들어진 오브젝트에 있는 메서드를 호출하는 작업이 반복된다.

이런 흐름에서 보통 각 오브젝트는 각자 호출할 오브젝트 생성에 능동적으로 참여한다.

풀어서 설명하자면 외부에서 오브젝트를 주입 받지 않고, 직접 생성하는 것이다.

앞 부분 초난감 DAO에서 본 것처럼 직접 ConnectionMaker()를 정하는 방식이다.

 

제어의 역전이란 이 흐름을 뒤집는 것이다. 

즉 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않는다. 당연히 생성하지도 않는다.

또 자신도 어떻게 만들어지고 어디서 사용되는 지를 알 수 없다.

모든 제어 권한을 자신이 아닌 DaoFactory 같은 대상에게 위임하기 때문이다. 이것이 바로 제어의 역전이다.

제어의 역전은 IoC(Inversion of Control)라고 하며 스프링은 대표적인 IoC프레임워크다.

이제 본격적으로 스프링이 제공하는 IoC에 대해 알아보자.

1.5 스프링의 IoC

  • 스프링이 IOC 방식으로 관리하는 오브젝트(객체)다.
  • 스프링이 직접 그 생성과 제어를 담당하는 오브젝트만 빈이라고 한다.

빈 팩토리과  애플리케이션 컨텍스트

  • 빈 팩토리는 스프링의 핵심 IoC 컨테이너다.
  • 애플리케이션 컨텍스트는 빈 팩토리의 기능을 확장한 IOC 컨테이너다. 
    빈 팩토리보다 많은 기능을 지원한다.

설정정보/ 설정 메타 정보

  • 스프링의 설정 정보란 빈 팩토리 또는 애플리케이션 컨텍스트가 IoC를 적용하기 위해 사용하는 메타 정보다.

컨테이너, IoC 컨테이너

  • IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC 컨테이너라고 한다.
    스프링 컨테이너라고도 자주 부른다.

싱글톤과 싱글톤 레지스트리

  • 싱글톤은 오직 오브젝트가 1개만 생성되는 디자인 패턴이다.
  • 스프링은 기본적으로 빈 오브젝트를 싱글톤으로 생성하고 컨테이너에서 관리한다.
  • 애플리케이션 컨텍스트는 싱글톤을 저장하고 관리하는 싱글톤 레지스트리다.
  • 싱글톤 레지스트리를 사용해 싱글톤의 단점을 모두 극복했다. (private 생성자, 스태틱 필드 정의 등)

스프링은 태생적으로 웹 엔터프라이즈 시스템을 위해 고안된 기술이다. 

웹은 보통 사용자들의 요청이 동시에 들어온다. 만약 요청이 들어올 때마다 오브젝트를 생성한다면 어떨까?

대규모 트래픽이 들어오는 웹 애플리케이션에서는 오브젝트를 생성하고 GC를 사용해 오브젝트를 제거하면서 서버에 많은 부하가 걸릴 것이다. 그러므로 오브젝트 1개를 만들어 사용하는 싱글톤이 효과적이다.

참고로 싱글톤으로 등록되는 스프링 빈 오브젝트는 무상태로 설계해야 한다.

1.7 의존관계 주입(DI)

드디어 DI가 등장했다. 먼저 의존관계에 정의해보자.

의존관계는 필드로 오브젝트를 가지는데, 그 오브젝트의 메서드를 사용하면 의존관계라고 한다.

의존관계는 단방향, 양방향 등 방향성이 있다.

스프링의 IoC 컨테이너는 사실 요즘 DI 컨테이너라고 많이 불려진다.

 

위 책의 예시에서 UserDao의 오브젝트가 런타임 시에 사용할 오브젝트가 어떤 클래스로 만든 것인지 미리 알 수가 없다.

프로그램이 시작되고 UserDao 오브젝트가 만들어지고 나서 런타임 시에 의존관계를 맺는 대상,

즉 실제 사용대상인 오브젝트를 의존 오브젝트라고 한다.

의존 관계 주입은 이렇게 구체적인 의존 오브젝트와 그것을 사용할 주체, 보통 클라이언트라고 부르는 오브젝트를 런타임 시에 연결해주는 작업을 말한다. 우리는 예시에서 인터페이스를 사용해 유연한 의존관계를 구축했다.

정리하면 의존관계 주입이란 다음과 같은 세 가지 조건을 충족하는 작업이다.

 

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

DI의 핵심은 설계 시점에는 알지 못했던 두 오브젝트의 관계를 맺도록 제 3의 존재(컨테이너)가 있다는 것이다.

참고로 의존관계 검색 방법도 있는데 보통 의존관계 주입이 더 좋다.

보통 의존관계 검색을 사용하는 시점은 애플리케이션 기동 시점이다.

애플리케이션 기동 시점에서 적어도 한 번은 의존관계 검색 방식을 사용해 오브젝트를 가져와야 한다.

스프링이 제공하는 기능의 99%가 DI를 사용하므로 DI에 대해 잘 알아두자.

기억해야할 것

  • 개발자가 객체를 설계할 때 가장 염두에 둬야할 사항은 바로 미래의 변화를 어떻게 대비할 것인가이다.
  • 변화의 성격에 따라 다르게 관리하자. 관심사의 분리.
  • 추상화로 설계가 유연해질 수 있었다. IoC와 DI 이해를 바탕으로 적용하자.
  • 오브젝트 팩토리, 오브젝트가 생성되고 다른 오브젝트와 관계를 맺는 작업의 제어권을 가진 클래스로 인해 
    핵심 로직을 수행하는 오브젝트들이 생성이나 선택에 대한 책임으로부터 자유로워졌다.

참고

  • 서블릿은 자바 엔터프라이즈 기술의 가장 기본이 되는 서비스 오브젝트다.
  • 서블릿은 대부분 멀티스레드 환경에서 싱글톤으로 동작한다.
  • 서블릿 클래스당 하나의 오브젝트만 만들어두고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해 동시에 사용한다.

 

제가 1장을 읽으면서 중요하다고 느낀 부분과 인상 깊게 느낀 부분을 정리해봤습니다.

더 많은 내용과 자세한 설명이 책에 담겨 있으므로 꼭 책을 읽어 보는 것이 좋을 것 같습니다.

이상으로 포스팅을 마칩니다. 감사합니다.

 

참고 자료

토비의 스프링 3.1 Vol. 1 (1장 오브젝트와 의존관계)

반응형

댓글