스프링

  • 자바를 기반으로 한 프레임워크로서, 자바의 본질인 객체지향 프로그래밍을 강조한다
  • 주로 오브젝트에 집중하며, 객체가 어떻게 생성되고, 다른 객체와 어떻게 상호작용하며, 설계되고 구현되어야 하는지에 대한 깊은 이해가 필요하다
  • 이러한 객체지향 설계와 구현을 강제하지 않지만, 효과적인 객체 사용과 개선 방법에 대해 명확한 가이드라인을 제공한다

DAO

  • DAO(Data Access Object)
    • DB를 통한 데이터 조회와 조작을 담당하는 객체
  • 자바빈(JavaBean)
    • JSP페이지의 디자인 부분과 로직부분을 나눔으로써 재사용성을 증가시키는 기능의 형태
    • 현재에는 아래와 같은 규약에 따라 만들어지는 오브젝트를 가리킨다 -기본 생성자 : 자바빈은 아무런 인자를 받지 않는 기본 생성자를 가져아한다 -> 자바빈은 툴이나 프레임워크에서 리플렉션을 이용하여 객체를 생성하기 때문 -리플렉션(Reflection) : 클래스, 메서드, 필드 등을 런타임에서 동적으로 검사하고 조작 할 수 있는 기능 -프로퍼티 : 멤버변수의 접근제어자는 private, 클래스와 set/get 메소드의 접근제어자는 public이며 set/get 메소드를 이용해 프로퍼티에 접근할 수 있다
  • User
      package springbook.user.domain
    
      public class User {
          String id;	
          String name;
          String password;
    		
          public String getId() {	
              return id;
          }
    		
          public void setId(String id) {	
              this.id = id;
          }
    		
          public String getName() {
              return name;
          }
    		
          public void setName(String name) {
              this.name = name
          }
    
          public String getPassword() {
              return password
          }
    
          public void setPassword(String password) {
              this.password = password
          }
      }
    
  • UserDao
      import java.sql.*;
        
      public class UserDao {
          public void add(User user) throws ClassNotFoundException, SQLException {
              Class.forName("com.mysql.jdbc.Driver");
              Connection c = DriverManager.getConnection(
                      "jdbc:mysql://localhost", "spring", "book");
        
              PreparedStatement ps = c.prepareStatement(
                      "insert into users(id, name, password) values(?,?,?)");
              ps.setString(1, user.getId());
              ps.setString(2, user.getName());
              ps.setString(3, user.getPassword());
        
              ps.executeUpdate();
        
              ps.close();
              c.close();
          }
              public User get(String id) throws ClassNotFoundException, SQLException {
                  Class.forName("com.mysql.jdbc.Driver");
                  Connection c = DriverManager.getConnection(
                          "jdbc:mysql://localhost", "root", "2092");
        
                  PreparedStatement ps = c.prepareStatement(
                          "select * from users where id = ?");
                  ps.setString(1, id);
        
                  ResultSet rs = ps.executeQuery();
                  rs.next();
                  User user = new User();
                  user.setId(rs.getString("id"));
                  user.setName(rs.getString("name"));
                  user.setPassword(rs.getString("password"));
        
                  rs.close();
                  ps.close();
                  c.close();
        
                  return user;
          }
      }
    

DAO의 분리

객체지향 기술은 가상의 추상세계 자체를 효과적으로 구성할 수 있고, 이를 자유롭고 편리하게 변경, 발전, 확장시킬 수 있는 기술적 특징 때문에 좀 더 번거로운 작업을 요구한다

객체를 설계할 때 가장 염두에 둬야 할 사항은 미래의 변화(요구사항, 운영 환경의 변화)에 대한 대비이다

  • 분리와 확장
    • 변화는 대체로 집중된 한 가지 관심에 대해 일어난다
    • 특정 작업으로 인해 관심이 다른 부분까지 영향을 받으면 안된다

관심사의 분리

  • 관심이 같은 것끼리는 하나의 객체 혹은 친한 객체로
  • 관심이 다른 것은 가능한 떨어져 영향을 주지 않도록

  • UserDao의 관심사항
    1. DB와 연결을 위한 커넥션을 어떻게 가져올까
    2. DB에 보낼 SQL 문장을 담을 Statement를 만들고 실행하는 것
    3. 작업이 끝나면 Statement와 Connection객체를 닫아줘서 시스템에 반환
  • UserDao의 문제점
    1. DB 커넥션을 가져오는 코드가 다른 관심사와 섞여 add() 메소드에 담겨 있다
    2. 동일한 코드가 get() 메소드에도 중복되어 있다 -> 이후에 수많은 DAO 메소드를 만들게 되면 같은 코드가 계속 중복되어 나타날 것이다
  • 중복 코드의 메소드 추출 -중복 코드를 독립적인 메소드로 만들어둔다

  • 중복을 제거한 UserDao
      public void add(User user) throws ClassNotFoundException, SQLException {
          Connection c = getConnection();
          ...
      }
        
      public User get(String id) throws ClassNotFoundException, SQLException {
          Connection c = getConnection();
          ...
      }
    
      private Connection getConnection() throws ClassNotFoundException, SQLException {
          Class.forName("com.mysql.jdbc.Driver");
          Connection c = DriverManager.getConnection(
              "jdbc:mysql://localhost/springbook", "spring", "book");
          return c;
      }
    
  • 변경점
    1. 특정 관심사에 대한 변경이 일어날 경우 그 관심이 집중되는 부분의 코드만 수정하면 된다
    2. 관심이 다른 코드에는 영향을 주지도 않고 독립적으로 존재한다

이렇게 기능과 실행 결과의 변화 없이 코드의 구조를 재조정하는 작업을 리팩토링(refactoring)이라고 하며, 위의 상황처럼 중복된 코드를 하나의 메소드로 뽑아내는 것을 리팩토링에서는 메소드 추출(extract method)기법이라고 한다

상속을 통한 확장

  • UserDao를 판매한다고 할 때 소스코드가 아닌 미리 컴파일된 클래스 바이너리 파일만 제공하면서 고객 스스로 원하는 DB 커넥션 생성 방식을 적용하게 하는 등 지속적인 변경에 자유롭게 할 수 있을까?
    • getConnection()을 추상 메소드로 만든다
    • 이후 고객들은 UserDao 클래스를 상속하여 서브클래스를 만들고 원하는 방식대로 getConnection() 메소드를 구현한다
  • 상속을 통한 확장 UserDao
      public void add(User user) throws ClassNotFoundException, SQLException {
          Connection c = getConnection();
          ...
      }
        
      public User get(String id) throws ClassNotFoundException, SQLException {
          Connection c = getConnection();
          ...
      }
    
      public abstract Connection getConnection() throws ClassNotFoundException, SQLException {
          /* 구현 코드가 제거된 추상메소드 */
          /* 구현은 서브클래스가 담당 */
      }
    
      public class NUserDao extends UserDao { 
          public Connection getConnection() throws ClassNotFoundException, SQLException {
              /* N 사 DB connection 생성코드 */
          }
      }
    	
      public class DUserDao extends UserDao {
          public Connection getConnection() throws ClassNotFoundException, SQLException {
              /* D 사 DB connection 생성코드 */
          }
      }
    
    • 이런식으로 슈퍼클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩 가능한 protected 메소드 등으로 만든 뒤 서브 클래스에서 구현하여 사용하도록 하는 방법을 디자인 패턴에서 템플릿 메소드 패턴(template method pattern)이라고 한다
    • 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것은 팩토리 메소드 패턴(factory method pattern)이라 부른다
  • 디자인 패턴
    • 소프트웨어 설계 시 발생하는 반복적인 문제들에 대한 해결책 중에서 많은 사람들이 인정한 모범 사례
  • 템플릿 메소드 패턴(template method pattern)
    • 상속을 통한 확장을 사용할 때 가장 대표적인 방법
    • 변하지 않는 기능은 슈퍼클래스에 만들어두고 자주 변경되며 확장할 기능은 서브클래스에서 만들도록 한다
  • 예시
     public abstract class Super {
         public void templateMethod() {
             //기본 알고리즘 코드
             hookMethod();
             abstractMethod();
             ...
         }
         protected void hookMethod() { }  /* 선택적으로 오버라이드 가능한 훅 메소드 */
         public abstract void abstractMethod(); /* 서브클래스에서 반드시 구현해야 하는 추상 메소드 */
     }
    
     public class Sub1 extends Super { /* 슈퍼클래스의 메소드를 오버라이드하거나 구현하여 기능 확장 */
         protected void hookMethod(){
             ...
         }
         public void abstractMethod() {
             ...
         }
     }
    
  • 팩토리 메소드 패턴(factory method pattern)
    • 상속을 통한 확장패턴이기에 템플릿 메소드 패턴과 비슷한 구조
    • 객체 생성의 책임을 서브클래스에 위임함으로써 객체 생성 코드를 캡슐화하고 코드의 유연성과 확장성을 높이는 디자인 패턴
  • 예시
     // Product Interface
     public interface Car {
         void drive();
     }
    	
     // Concrete Product Classes
     public class Sedan implements Car {
         @Override
         public void drive() {
             System.out.println("Driving a sedan");
         }
     }
    	
     public class SUV implements Car {
         @Override
         public void drive() {
             System.out.println("Driving an SUV");
         }
     }
    	
     // Factory Class
     public abstract class CarFactory {
         public abstract Car createCar();
    	
         public void driveCar() {
             Car car = createCar();
             car.drive();
         }
     }
    	
     public class SedanFactory extends CarFactory {
         @Override
         public Car createCar() {
             return new Sedan();
         }
     }
    	
     public class SUVFactory extends CarFactory {
         @Override
         public Car createCar() {
             return new SUV();
         }
     }
    	
     // Client Code
     public class Client {
         public static void main(String[] args) {
             CarFactory sedanFactory = new SedanFactory();
             CarFactory suvFactory = new SUVFactory();
    	
             sedanFactory.driveCar(); // Output: Driving a sedan
             suvFactory.driveCar(); // Output: Driving an SUV
         }
     }
    
    
  • 차이점 : 템플릿 메소드 패턴은 알고리즘의 구조를 정의하고 세부 구현을 서브클래스에 위임하는 반면, 팩토리 메소드 패턴은 객체 생성의 책임을 서브클래스에 위임하여 객체 생성 코드를 캡슐화한다

  • 상속을 통한 확장의 단점
    • 자바는 클래스의 다중상속을 허용하지 않는다
      • 만약 UserDao가 이미 다른 목적을 위해 상속을 사용하고 있다면 문제가 된다(새로운 상속구조로 만들어도 후에 다른 목적으로 상속을 적용하기 힘들다)
    • 상속을 통한 상하위 클래스의 관계가 밀접하다 (관심이 다른 기능을 분리하고, 확장성도 좋지만 여전히 상속관계는 긴밀한 결합을 허용한다)
    • 확장 기능을 다른 클래스에 적용할 수 없다(코드 중복)

DAO의 확장

관심들은 변화의 성격이 다르다 변화의 성격이 다르다는 것은 이유와 시기, 주기 등이 다르다는 것이다 위에서는 변화의 성격이 다른 것을 분리해서, 서로 영향을 주지 않은 채로 필요한 시점에 독립적으로 변경할 수 있게 하기 위해 추상 클래스를 만들고 서브클래스에서 상속하게 하였다

클래스의 분리

이때까지 했던 독립 메소드를 통한 분리, 상하위 클래스로 분리가 아닌 완전한 독립 클래스로 분리한다 DB 커넥션과 관련된 부분을 아예 별도의 클래스에 담고 UserDao가 이용하게 한다

  • 독립된 DB 커넥션 기능을 하는 클래스
     public class SimpleConnectionMaker {
         public Connection makeNewConnection() throws ClassNotFoundException, SQLException {
             Class.forName("com.mysql.jdbc.Driver");
             Connection c = DriverManager.getConnection("jdbc:mysql://localhost/springbook", "spring", "book");
             return c;
         }
     }
    
  • 바뀐 UserDao
     public class UserDao {
         private SimpleConnectionMaker SimpleConnectionMaker;
    		
         public UserDao() {
         SimpleConnectionMaker = new SimpleConnectionMaker();
         }
         public void add(User user) throws ClassNotFoundException, SQLException {
             Connection c = SimpleConnectionMaker.makeNewConnection();
             ...
         }
         public void get(String id) throws ClassNotFoundException, SQLException {
             Connection c = SimpleConnectionMaker.makeNewConnection();
             ...
         }
     }
    

그러나 UserDao의 코드가 특정 클래스에 종속되어 있기 때문에 상속을 통한 확장으로 해결했던 문제점으로 다시 돌아오게 되었다

인터페이스의 도입

인터페이스 : 다른 클래스를 작성할 때 기본이 되는 틀을 제공하면서, 다른 클래스 사이의 중간 매개 역할까지 담당하는 일종의 추상 클래스

인터페이스에는 구현 방법은 나타나 있지 않고 구현하는 클래스들이 결정할 일이다

  • ConnectionMaker 인터페이스
      package springbook.user.dao
    
      public interface ConnectionMaker {
    	
          public Connection makeConnection() throws ClassNotFoundException, SQLException;
      }
    

    고객들은 ConnectionMaker 인터페이스를 구현한 클래스를 만들고 메소드를 작성해주면 된다

  • 구현 클래스
      package springbook.user.dao
    
      public class DConnectionMaker implements ConnectionMaker {
          @Override
          public Connection makeConnection() throws ClassNotFoundException, SQLException {
              // 고객의 방법으로 Connection을 생성하는 코드
          }
      }
    
  • 바뀐 UserDao
     public class UserDao {
         private ConnectionMaker ConnectionMaker;
    		
         public UserDao() {
             ConnectionMaker = new DConnectionMaker();
         }
         public void add(User user) throws ClassNotFoundException, SQLException {
             Connection c = ConnectionMaker.makeConnection();
             ...
         }
         public void get(String id) throws ClassNotFoundException, SQLException {
             Connection c = ConnectionMaker.makeConnection();
             ...
         }
     }
    

    그러나 생성자 코드에 인터페이스를 구현한 클래스의 이름이 나타난다(여전히 사용할 구현 클래스의 정보를 알아야 하기에 종속된 상황)

관계설정 책임의 분리

사용할 구현 클래스의 이름을 알아야 한다는 것은 UserDao와 UserDao가 사용할 특정 구현 클래스 사이의 관계를 설정하주는 것에 관한 관심이다 이 관심을 담은 코드를 분리하지 않으면 독립적으로 확장 가능한 클래스가 될 수 없다

UserDao의 클라이언트에서 UserDao를 사용하기 전에, UserDao가 어떤 구현 클래스를 사용할지를 결정하도록 하자

UserDao에서 사용할 클래스 즉 오브젝트를 UserDao의 코드 내에서 만들 필요는 없다 메소드 파라미터나 생성자 파라미터를 이용하자

  • 수정된 생성자 코드
      public UserDao(ConnectionMaker connectionMaker) {
          this.connectionMaker = connectionMaker;
      }
    

    UserDao에는 더이상 다른 관심사항, 책임이 없다

원칙과 패턴

  • 개방 폐쇄 원칙
    • 클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다
  • 응집도와 결합도
    • 응집도 : 모듈 내부의 기능적인 집중 정도
    • 결합도 : 모듈과 모듈 사이의 의존 정도
  • 높은 응집도와 낮은 결합도
    • 응집도가 낮다면 변경이 필요할 때 필요한 부분을 찾아내는 것도, 변경한 것이 다른 기능에 영향을 주는지도 확인해야한다
    • 결합도가 높다면 하나의 오브젝트가 변경이 일어날 때 관계를 맺는 다른 오브젝트에게도 변경에 대한 요구가 전파된다
    • 응집도가 높을수록 결합도가 낮을수록 좋다
  • 객체지향 설계 원칙(SOLID)
    • SRP : 단일 책임 원칙
    • OCP : 개방 폐쇄 원칙
    • LSP : 리스코프 치환 원칙
      • ISP : 인터페이스 분리 원칙
    • DIP : 의존관계 역전 원칙
  • 전략 패턴
    • 객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화 하는 인터페이스를 정의하여, 객체의 행위를 동적으로 바꾸고 싶은 경우 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 디자인 패턴
  • 전략 패턴의 구성 요소
    • Context: 기능을 수행하는 데 필요한 알고리즘을 외부에서 주입받아 사용
    • Strategy Interface: 알고리즘을 정의하는 인터페이스
    • Concrete Strategy: 알고리즘을 구체적으로 구현한 클래스
  • UserDao의 전략 패턴
    • UserDao : Context
    • ConnectionMaker : Strategy Interface
    • DConnectionMaker : 고객들의 방식대로 구현한 클래스(Concrete Strategy)

제어의 역전

객체의 생성 방법을 결정하고 그렇게 만들어진 객체를 돌려주는 오브젝트를 팩토리라고 한다

  • DaoFactory
      package springbook.user.dao;
      ...
      public class DaoFactory { 
          public UserDao userDao() {
              ConnectionMaker connectionMaker = new DConnectionMaker();
              UserDao userDao = new UserDao(connectionMaker);
    			
              return userDao;
          }
      }
    
  • DaoFactory를 사용하는 클래스
      public class UserDaoTest {
          public static void main(String[] args) throws ClassNotFoundException, SQLException {
              UserDao dao = new DaoFactory().userDao();
              ...
          }
      }
    

이런식으로 다른 것들은 신경 쓰지 않고 팩토리로부터 오브젝트를 받아 사용하기만 하면 된다

오브젝트 팩토리의 활용

  • 코드 중복 상황
      public class DaoFactory {
          public UserDao userDao() {
              return new UserDao(new DConnectionMaker());
          }
          public AccountDao accountDao() {
              return new AccountDao(new DConnectionMaker());
          }
          public MessageDao messageDaoO {
              return new MessageDao(new DConnectionMaker());
          }
      }
    
  • 메소드 추출로 중복 해결
      public class DaoFactory {
          public UserDao userDao() {
              return new UserDao(connectionMaker());
          }
          public AccountDao accountDao() {
              return new AccountDao(connectionMaker());
          }
          public MessageDao messageDaoO {
              return new MessageDao(connectionMaker());
          }
          public ConnectionMaker connectionMaker() {
              return new DConnectionMaker();
          }
      }
    

제어권의 이전을 통한 제어관계 역전

제어의 역전(IoC) : 프로그램의 제어 흐름 구조가 뒤바뀌는 것

일반적인 프로그램의 흐름 : 사용할 오브젝트 결정 -> 생성 -> 호출 -> 메소드 안에서 결정 -> 호출

  • 제어의 역전의 예시
    • Servlet, JSP, EJB
  • 디자인 패턴에서의 제어의 역전
    • 템플릿 메소드
  • 프레임워크와 라이브러리
    • 라이브러리 : 애플리케이션 코드가 애플리케이션의 흐름을 제어하고 필요할 때 능동적으로 사용
    • 프레임워크 : 프레임워크가 흐름을 주도하는 중에 개발자가 만든 애플리케이션 코드를 사용

스프링의 IOC

스프링(Spring)은 IoC를 극한까지 적용하고 있는 프레임워크다

  • Bean : 스프링 IoC 컨테이너가 관리하는 오브젝트
  • Bean Factory : Bean 오브젝트를 생성하고 관리하는 IoC 오브젝트
  • Application Context : Bean Factory를 확장시킨 컨테이너

DaoFactory를 사용하는 Application Context

DaoFactory를 스프링의 Application Context가 사용할 수 있는 설정정보로 만들어보자

  • Application Context를 위한 오브젝트 설정 클래스
      import org.springframework.context.annotation.Bean;	
      import org.springframework.context.annotation.Configuration;
      ...
    	
      @Configuration /* 설정정보 클래스로 인식하기 위함 */
      public class DaoFactory {
          @Bean /* 리턴값이 Bean객체로 관리되기 위함 */
          public UserDao userDao() {
              return new UserDao(connectionMaker());
          }
    
          @Bean 
          public ConnectionMaker connectionMaker() {
              return new DConnectionMaker();
          }
      }
    
  • Application Context를 적용
      public class UserDaoTest {
          public static void main(String[] args) throws ClassNotFoundException, SQLException {
          Applicationcontext context = new AnnotationConfigApplicationContext(DaoFactory.class);
          UserDao dao = context.getBean("userDao", UserDao.class);
    		
          ...
          }
      }
    
  • getBean()
    • Application Context 인터페이스에 정의된 메소드
    • 주어진 이름 또는 타입을 기반으로 등록된 Bean 오브젝트를 반환
    • 역할 : Bean 객체 검색, 생성, 의존성 주입

      Application Context 동작방식

  • 장점
    1. 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다
    2. 종합 IoC 서비스를 제공한다
    3. 다양한 Bean 검색 방법을 제공한다

싱글톤 레지스트리와 오브젝트 스코프

DaoFactory의 userDao() 를 두 번 호출하여 생성된 오브젝트가 같을까? (동일한 정보를 담는 오브젝트가 아닌 완전히 동일한 오브젝트인지)

  • Application Context를 적용한 오브젝트 출력
      Applicationcontext context = new
      AnnotationConfigApplicationContext(DaoFactory.class);
    
      UserDao dao3 = context.getBean("userDao", UserDao.class);
      UserDao dao4 = context.getBean("userDao", UserDao.class);
    	
      System.out.printin(dao3); 
      System.out.printin(dao4);
    

    오브젝트 팩토리와는 다르게 Application Context를 적용하면 여러번 호출해도 같은 오브젝트를 반환한다

왜냐하면 Application Context는 Singleton을 저장하고 관리하는 Singleton registry이기도 하기 때문이다

싱글톤 패턴의 한계

  • 자바에서의 싱글톤 구현 방법
    • 클래스 밖에서는 오브젝트를 생성하지 못하도록 생성자를 private으로 만든다
    • 생성된 싱글톤 오브젝트를 저장할수 있는 자신과 같은 타입의 스태틱 필드를 정의한다
    • 스태틱 팩토리 메소드인 getlnstance()를 만들고 이 메소드가 최초로 호출되는 시점에서 한번만 오브젝트가 만들어지게 한다. 생성된 오브젝트는 스태틱 필드에 저장된다. 또는 스태틱 필드의 초기 값으로 오브젝트를 미리 만들어둘 수도 있다.
    • 한번 오브젝트(싱글톤)가 만들어지고 난 후에는 getlnstance() 메소드를 통해 이미 만들어져 스태틱 필드에 저장해둔 오브젝트를 넘 겨준다.
  • 문제점
    1. 생상자가 private이다
    2. 테스트가 힘들다
    3. 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다
    4. 싱글톤의 사용은 전역 상태를 만들 수 있다

    스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공하는 싱글톤 레지스트리이다

    • 싱글톤 방식의 클래스도 public 생성자를 가질 수 있다
    • 테스트 환경에서 자유롭게 오브젝트를 만들 수 있다

싱글톤과 오브젝트의 상태

싱글톤은 멀티스레드 환경이라면 여러 스레드가 동시에 접근해서 사용할 수 있어 상태 관리에 주의를 기울여야 한다 -> 이상한 값을 읽어올 수 있음

스프링 빈의 스코프

빈의 스코프 : Bean이 생성되고, 존재하고, 적용되는 범위

기본적으로 싱글톤 스코프이나 다른 여러가지 스코프도 사용 가능

의존관계 주입(DI)

스프링이 제공하는 IoC 기능은 제어권을 외부에 주는 것만이 아니고 대표적인 동작원리로 의존관계 주입이 있다

DI(Dependency Injection) : 런타임 시에 외부에서 의존관계를 맺을 오브젝트를 주입해주는 기술

의존관계에는 방향성이 있다

지금까지 작업해온 UserDao와 ConnectionMaker는 UserDao가 ConnectionMaker를 사용하는 ‘사용에 대한 의존관계’이다 인터페이스 구현클래스에 대해서는 의존관계가 아니다

  • 런타임 의존관계 오브젝트 의존관계
    • 애플리케이션이 실행되는 동안에 결정되는 객체 간의 의존 관계
  • DI 방식
    1. 생성자 메소드
    2. 수정자 메소드
    3. 일반 메소드
  • 의존관계 주입 코드
      public class UserDao{
          private ConnectionMaker connectionMaker;
    
          public UserDao(ConnectionMaker connectionMaker) {
              this.connectionMaker = connectionMaker;
          }
      }
    

    의존관계 검색과 주입

    의존관계 검색(Dependency Lookup) : 자신이 필요로 하는 의존 오브젝트를 능독적으로 검색

  • DI와의 차이
    • 의존관계를 맺을 오브젝트 결정, 생성 -> 외부
    • 해당 오브젝트를 가져오는 작업 -> 스스로 요청(외부 주입X)
  • 의존관계 검색
      public UserDao() {
          DaoFactory daoFactory = new DaoFactory();
          this.connectionMaker = daoFactory.connectionMaker();
      }
    
  • DI방식은 Client도 Bean Object여야함
  • DL은 아님

  • DI 방식의 장점
    • 코드에는 런타임 클래스에 대한 의존관계가 나타나지 않고, 인터페이스를 통한 결합도 낮은 코드
    • 설정 정보만 변경해주면 전체에 적용되어 변화에 자유로움

XML을 이용한 설정

스프링은 자바 클래스를 이용하는 것 이외에도, 다양한 방법을 통해 DI 의존관계 설정정보를 만들 수 있다.

  • XML의 장점
    1. 다루기 쉽다
    2. 빌드 작업이 없다
    3. 환경이 달라져도 변경이 쉽다
    4. 정해진 포맷을 따라 작성됐는지 확인이 쉽다
  • userDao 빈 설정
      <beans>
          <bean id="userDao" class="springbook.dao.UserDao">
              <property name="connectionMaker" ref="connectionMaker" />
          </bean>
      <beans>
    
  • 자바코드와 대응하는 XML
    • @Configuration = <beans>
    • @Bean = <bean>
    • Bean 이름 = <bean id="Bean이름">
    • Bean 클래스 = <bean id="Bean클래스">
    • 프로퍼티 = <property name="프로퍼티이름" ref="주입할 Bean 이름">

    Applicationcontext context = new GenericXmlApplicationContext(“/applicationContext.xml”);

    클래스패스 루트로부터의 경로 대신 같은 클래스패스에 있는 오브젝트를 넘겨 상대적으로 지정해주는 ClassPathXmlApplicationContext

    new ClassPathXmlApplicationContext(“daoContext.xml”, UserDao.class);

카테고리:

업데이트:

댓글남기기