1. 오브젝트와 의존관계

오브젝트와 의존관계

1. 초난감 DAO

문제점

  • 중복코드

  • 변경사항에 빠른 대체 불가

  • User

    ```java 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
```java
public class UserDao {
  private static UserDao instance;

  public static synchronized UserDao getInstance() {
    if (instance == null) {
      instance = new UserDao();
    }
    return instance;
  }

  public void add(User user) {
    // JDBC 설정

    // 인설트

    // 자원 반환
  }

  public User get(String id) {
    // JDBC 설정

    // 조회

    // 자원 반환
    User user = new User();
    user.setId(id);
    return user;
  }
}
  • Test

    @Test
    public void test_1_3() {
      UserDao dao = new UserDao();
    
      User user = new User();
      user.setId("open");
      user.setName("소명섭");
      user.setPassword("1234");
    
      dao.add(user);
      System.out.println(user.getId() + " 등록 성공");
    
      User user2 = dao.get(user.getId());
      System.out.println("user2 = " + user2);
      System.out.println(user.getId() + " 조회 성공");
    }

2. DAO 분리

2.1 관심사 분리

  • 변경사항이 발생시 필요한 작업이 최소화 될 수 있도록 하기 위함

  • 분리와 확장에 대한 개념 (OOP 개념 중 OCP 개념)

2.2 커넥션 만들기의 추출

초난감 DAO에서 add 메서드는 3가지의 관심(기능)을 갖고 있다. 메서드는 1가지일. 즉, 1가지 관심을 갖고 일을 해야한다. 그래야 수정시 분석시간도 줄고, 수정할 내용을 최소화 할 수 있기 때문

add 메서드의 3가지 관심사 1. DB 연결 2. 조회, 등록, 수정, 삭제 (CRUD) 3. 자원 반환

즉, 3가지 관심사를 1개의 메서드로 각각 분리를 해야한다.

  • DB 연결

    public Connection getConnection() throws SQLException {
      // DB 연결
      return DriverManager.getConnection("jdbc:벤더사", "so", "1234");
    }
  • 반환

    public void resourceClear(Connection connection) {
      try {
        // 그외 prestatement 등 자원리소스 반환 
        connection.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  • CRUD

    // 등록
    public void add(User user) {
      // DB 연결
      Connection connection = getConnection();  // 메서드로 분리 후 호출
      // 인설트
    
      // 자원 반환
      resourceClear(connection);
    }
    
    // 조회
    public User get(String id) {
      // DB 연결
      Connection connection = getConnection();  // 메서드로 분리 후 호출
      // 조회
    
      // 자원 반환
      resourceClear(connection);
    }

2.3 DB 커넥션 만들기의 독립

UserDao가 확장이 되어야한다!!!

Oralce DB -> MySQL DB로 변경발생

  1. UserDao를 추상클래스 or 인터페이스로 구현

  2. OralceDB / MySQLDB를 구현클래스로 구현 -> UserDao 확장

  3. 추상클래스 AbstractUserDao

    public abstract class AbstractUserDao {
    public abstract Connection getConnection(AbstractUserDao dao);
    
    public abstract void add();   // 추가내용
    // ... 다양한 작업 추가
    
    public abstract void clear(); // 추가내용
    
    // 템플릿 메서드 활용 -> 호출쪽에서 호출을 하겠지?
    public final void insertCustomer() throws SQLException {
      Connection connection = getConnection(this);
      PreparedStatement preparedStatement = connection.prepareStatement("sqlss");
      add();
      clear(connection, preparedStatement);
    }
    }
  4. NUserDao

    public class NUserDao extends AbstractUserDao {
    
    @Override
    public Connection getConnection(AbstractUserDao dao) {
      // N사 생성코드
      System.out.println("N사 dao DB 연결");
      System.out.println(dao);
      return null;
    }
    }
  5. DUserDao

    public class DUserDao extends AbstractUserDao {
    
    @Override
    public Connection getConnection(AbstractUserDao dao) {
      // D사 생성코드
      System.out.println("D사 dao DB 연결");
      System.out.println(dao);
      return null;
    }
    }
  6. Test

    @Test
    public void test_1_3_1() {
      AbstractUserDao dao = new DUserDao();
      AbstractUserDao dao2 = new NUserDao();
      try {
        dao.insertCustomer();   // D사 연결
        dao2.insertCustomer();  // N사 연결
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }

3. DAO의 확장

Dao에서 커넥션 부분을 인터페이스로 분리 커넥션 부분을 분리함으로써 UserDao에서 커넥션 부분을 수정할 필요가 없어졌다. 즉, 커넥션 부분 수정 발생시 커넥션 해당클래스를 수정하거나, 추가만시키면 언제든지 코드수정이 필요없이 적용이 가능해진다. 상속보다 분리를 사용하자는 이런 관점에서 유익함을 주기 때문이고, 디자인패턴 공부했을때 중요한 원칙

  • ConnectionMaker 인터페이스

    public interface ConnectionMaker {
    Connection makeConnection();
    }
  • DConnectionMaker 구현클래스

    public class DConnectionMaker implements ConnectionMaker {
    @Override
    public Connection makeConnection() {
      System.out.println("D사 커넥션 만들기");
      return null;
    }
    }
  • NConnectionMaker 구현클래스

    public class NConnectionMaker implements ConnectionMaker {
    @Override
    public Connection makeConnection() {
      System.out.println("D사 커넥션 만들기");
      return null;
    }
    }
  • Test

    ```java @Test public void test_1_12() {

    / 요구사항 1. 새로운 K사 DB 적용을 할 겁니다. 반영해주세요 /

    UserDao dao = new UserDao(new DConnectionMaker()); // 이 부분만 수정하고 K사 추가시켜서 인터페이스대로 구현만 하면 끝

// 추가 적용한부분 
UserDao dao = new UserDao(new KConnectionMaker());  // 위 기존코드는 삭제하고 KConnection 구현만하면 반영 끝.
dao.get("1");

}

- 추가 KConnectionMaker 구현클래스
  추가시키기만 하면 끝 / UserDao 소스는 수정하나도 안해도 됨. -> 이런것이 분리의 장점이 된다
```java
public class KConnectionMaker implements ConnectionMaker {
  @Override
  public Connection makeConnection() {
    System.out.println("K사 커넥션 만들기");
    return null;
  }
}
  • 만약 이렇게 안했다면? 어떘을까?

    UserDao의 getConnection 메서드를 계속 수정해야할 것이다. 이렇게 수정하다가 또 롤백해주세요.

    수정하다보면... 어쩌다가 ? 버그를 만들어 낼 수도 있게되므로 잠재적 버그가 항상 존재하는 코드가 되는 것이다.

public Connection getConnection() throws SQLException {
  // DB 연결
  return DriverManager.getConnection("jdbc:벤더사", "so", "1234");  // 수정대상 부분
}

3.4 원칙과 패턴

OOP 5대원 칙 SOLID

  • S : SRP : 단일 책임 원칙

  • O : OCP : 개방 폐쇄 원칙

  • L : LSP : 리스코프 치환 원칙

  • I : ISP : 인터페이스 분리 원칙

  • D : DIP : 의존관계 역전 원칙

이 모든 내용은 변경 최소화, 유지보수성 관점에서 바라보면 된다.

SRP (단일 책임 원칙)

클래스는 한가지 일을, 메서드는 한가지 기능 이런식으로 구성을 해야한다. 클래스가 너무 많은 일을 하면, 분석 시간도 늘어나고, 메서드가 앞장에서 본것처럼 초난감 DAO의 UserDao.add() 같은 메서드는 3가지 관심(기능)을 갖고 일을 한다. 그러다보니 중복코드도 내재되고, 신경써야할 것도 많아지는데 이를 1가지로 구성하면, 수정을 해야할 때 더 적은 노력이면 충분하다는 것이다. 즉, 변경에 대해서 한가지만 고쳐야 한다는 관점

OCP (개방 폐쇄 원칙)

확장에 열려 있고, 수정에 닫혀 있다. 클래스를 확장할 때 다른 클래스는 건드리면 안된다는 내용이다. 그리고 SRP에서 언급한 것 처럼 수정할 때 다른데 영향을 미쳐서는 안된다는 것이다. (FP의 기반이 된다)

LSP (리스코프 치환 원칙)

다형성에 관한 내용이다. 상위객체(추상, 상속, 인터페이스)로 코딩을 해야하고, 서브 클래스로 데이터를 주고 받거나 실행 할때 아무 문제가 없어야 한다는 원칙.

생각해보면 파라미터(매개변수)로 넘길 때는 서브클래스의 하위호환이 가능해야하기 때문에 상위개념으로 항상 정의가 되어 있어야한다.

ISP (인터페이스 분리 원칙)

인터페이스로 분리해야하는 이유는 너무너무 많은 곳에서 이야기하고 있는 내용이다. 지금 까지 살펴본 내용처럼 인터페이스로 구분을 해놓으면, 구현할 때 인터페이스의 규칙에 맞게 구현을 하면되고, 사용할 때 서브클래스(구현체)를 통해서 내용을 담으면 되기 때문이다.

DIP (의존관계 역전 원칙)

고수준 모듈은 저수준의 모듈에 의존하면 안된다. -> 방향성 문제다. 항상 하위가 상위를 바라볼 수 있도록 해야 수정작업이 수월하다

이 두 모듈 모두 다른 추상화 된 것에 의존해야한다. -> 각 모듈은 분리가 되어 각각의 추상화 된것에 의존해서 구현되어야 수정작업이 수월하다

추상화 된 것은 구체적인 것에 의존하면 안된다. 반대로 구체적인 것이 추상화 된 것에 의존해야한다. -> 클래스다이어그램을 생각해보자 (상속, 인터페이스 등) 화살표 방향성 하위->상위로

수정작업이 어려운 이유 1. 영향도 2. 재사용성 부족 위 2가지 때문에 수정이 힘들다면 소프트웨어 품질이 나쁜 것이다. 이유는 간단하다. 수정이 편해야한다는것!그래서 OOP에서 SOLID 원칙이 중요한 것

높은 응집도와 낮은 결합도

  • 높은 응집도

    클래스 내의 정보가 강하게 결합되어 있어야한다는 것.
    즉, 필드, 메서드가 항상 연관되어 있어야하고, 어떤 연관없는 내용이 있다면 응집도가 낮다.
    낮으면 -> 1가지일이 아닌 2가지 이상의 일을 하고 있을 확률이 높다. 즉 SRP에 위배될 것이다.
    2. 재사용성 부족이 나타난다.
  • 낮은 결합도

    낮은 결합도가 중요한 이유는. ISP 관점이 좀 강하다.
    각 클래스간의 관계 분리를 통해서 낮은 또는 느슨한 결합을 해야 수정이 용이하다는 것이다.
    강하면 -> 수정시 1. 영향도 때문에 영향도분석까지 하는... 미친듯이 코드분석을 해야겠지?? 그러면 답도없는거야

전략 패턴

전략패턴을 언급하고 있다. 스프링에서 전략패턴은 ApplicationContext가 가장 대표적인 케이스가 아닌가 싶다. 디자인패턴 중 가장 유용한 패턴 중하나이고, 스프링에서 자주 사용한다. 예를들어, DB 변경 작업도 전략패턴을 구현해도 되는 부분이 필요할 수 있다.

4 제어의 역전 (IoC)

DaoFactory

  • ~Dao 생성 책임 클래스

  • 수정 전 ConnectionMaker 가 new로 구체적인 생성 진행중 -> ConnectionMaker가 DaoFactory 내부에서 구체적으로 직접관여 중 이럴 경우 단점은... 역시 변경일 때겠지?

    public class DaoFactory {
    
    public UserDao userDao() {
      return new UserDao(new DConnectionMaker());
    }
    
    public AccountDao accountDao() {
      return new AccountDao(new DConnectionMaker());
    }
    
    public MessageDao messageDao() {
      return new MessageDao(new DConnectionMaker());
    }
    }
  • 수정 후 ConnectionMaker를 생성자 파라미터로 받아서 적용 ConnectionMaker의 선정 책임을 외부로 돌림

public class DaoFactory {

  ConnectionMaker connectionMaker;  // 추가 has a 관계

  public DaoFactory(ConnectionMaker connectionMaker){
    this.connectionMaker = connectionMaker;
  }

  public UserDao userDao() {
    return new UserDao(this.connectionMaker);
  }

  public AccountDao accountDao() {
    return new AccountDao(this.connectionMaker);
  }

  public MessageDao messageDao() {
    return new MessageDao(this.connectionMaker);
  }

  // 책에서는 이걸 호출 함
  public ConnectionMaker connectionMaker(){
    return new DConnectionMaker();
  }
}

중복문제의 해결 -> 메서드추출, 클래스분리 리팩토링

제어의 역전이란

객체의 생성 관리.. 등 주체가 내가 아니다. 타인, 즉 외부가 관리의 주체가 되는 현상. 쉽게, 제어권이 역전됐다는 것이다. -> 제어 권한이 나한테 있는것이 아니라 다른사람(컨테이너)한테 있다. -> 디자인패턴 활용 (템플릿메서드, 팩토리메서드, 전략 등)

프레임워크와 라이브러리 차이

프레임워크 > 라이브러리

  • 라이브러리 어떤 문제해결을 위한 기능 제공. 예를들면 엑셀다운로드 하고싶은데... 이걸 도와주는 이미 만들어져있는 API를 통해 문제해결을 할 수 있는 수준의 API 집합

  • 프레임워크 어떤 문제해결을 위한 통합적 API 제공. 내부적 기능활용과 프로세스 흐름제어 등 어떤 문제해결(시스템같은)을 위해 모든 것을 제공해 줄 수 있는 API 집합. 틀, 구조, 확장 모든게 가능하고 가장 중요한건 제어개념이 포함되어야 한다. 스프링의 예로 IoC컨테이너, DI 이런 흐름제어 뿐 아니라 기능활용 제공 등. 어떤걸 해결하기 위한 통합적 API 집합

5 스프링의 IoC

  1. 빈팩토리 (BeanFactory) - 상위

  2. 애플리케이션 컨텍스트 (ApplicationContext) - 하위 : 가장 많이 사용 됨

BeanFactory(상위) <- ApplicationContext(하위)

설정 관련 어노테이션

  • @Configuration / @Bean 메서드명 -> 호출시 ID로 작용

    @Configuration  // -> 설정 파일이란 마킹
    public class DaoFactory {
      ConnectionMaker connectionMaker;
    
      @Bean         // -> Bean이란 마킹 
      public UserDao userDao() {
        this.connectionMaker = new DConnectionMaker();
        UserDao userDao = new UserDao(connectionMaker);
        return new UserDao();
      }
    
      @Bean
      public AccountDao accountDao() {
        return new AccountDao(this.connectionMaker);
      }
    
      @Bean
      public MessageDao messageDao() {
        return new MessageDao(this.connectionMaker);
      }
    }
  • Test

    @Test
    public void test1_19() {
      ApplicationContext context = 
          new AnnotationConfigApplicationContext(DaoFactory.class); // @Configuraion 객체 
      UserDao userDao = context.getBean("userDao", UserDao.class);  // 메서드명, 타입(반환타입추론)
      Object userDao = context.getBean("userDao");                  // 메서드명, 생략->Object 반환
      userDao.get("1");
    }
    
    // BeanFactory 일부
    public interface BeanFactory {
      String FACTORY_BEAN_PREFIX = "&";
      Object getBean(String var1) throws BeansException;
      <T> T getBean(String var1, Class<T> var2) throws BeansException;
      ...
      ...

getBean메서드 -> 빈을 검색하는 다양한 방식

  1. 빈의이름

  2. 타입

  3. 어노테이션

스프링 IoC 용어정리

  1. bean 스프링이 관리하는 객체를 스프링에서는 bean 이라함. 스프링 컨테이너가 관리 안하는 객체는 bean 이라 안함

  2. bean facotry 스프링컨테이너. bean을 관리하는 또 다른 객체

  3. application context

  4. 설정저보 / 설정 메타정보

  5. 컨테이너 또는 IoC 컨테이너

  6. 스프링 프레임워크

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

기본 스코프는 싱글턴이다. 1. 싱글턴 (singleton) - default

  • 스프링컨테이너에 의해 한번 로딩 된 후 어플리케이션이 죽을 때 까지 존재 (단, 인스턴스 1개)

    1. 프로토타입 (prototype)

  • 스프링컨테이너에 의해 한번 로딩 된후 어플리케이션이 죽을 때 까지 존재 (단, 요청시마다 새로운 인스턴스로 반환)

    1. 요청 (request)

  • request로 요청들어온 객체에 대해 반환 된 후 삭제 됨. 꽤 유용할듯

    1. 세션 (session)

  • 한 세션이 종료 될 때까지 존재 한 후 삭제. 웹의 세션과 (웹기반)

  // 싱글턴 구현
  public class UserDao{
    private ConnectionMaker connectionMaker;
    private static UserDao instance; // 싱글턴

  public static synchronized UserDao getInstance() {
    if (instance == null) {
      instance = new UserDao();
    }
    return instance;
  }

  // 테스트
  @Test
  public void test_1_20_21() {
    DaoFactory daoFactory = new DaoFactory();
    UserDao dao1 = daoFactory.userDao();
    UserDao dao2 = daoFactory.userDao();

    System.out.println("dao1 = " + dao1);
    System.out.println("dao2 = " + dao2);

    ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);

    UserDao userDao1 = context.getBean("userDao", UserDao.class);
    UserDao userDao2 = context.getBean("userDao", UserDao.class);

    System.out.println("userDao1 = " + userDao1);
    System.out.println("userDao2 = " + userDao2);
  }

싱글턴이 멀티스레드 환경에서 주의 사항

  1. 전역상태로 만듬

  2. 상속불가

  3. 테스트힘듬

  4. 하나로 만드는것 자체가 실제로 불가능에 가까움... 주의필요

7. 의존관계 주입 (DI)

7.1 제어의 역전과 의존관계 주입

DI란 의존성 주입, 의존성 주입이란, 호출하는 쪽이 오브젝트를 직접 관리, 생성하는 것이 아니라, 제 3자(컨테이너)에게 관리 및 생성의 책임을 넘기고 (IoC) 이를 통해 객체주입 받는 행위(DI). 즉, 객체의 주입을 누군가에게 의존해서 받는 것을 DI라 함.

7.2 런타입 의존관계 설정

A,B의 has a ~ 관계에서 A가 B를 갖는다A->B로 표현하며, A는 B를 갖고 있기 때문에 B의 변경에 영향을 받게 된다. 따라서 B는 A와 상관이 없으므로 B가 변경되더라도 A를 신경쓸 필요가 없는 것! 항상 영향도 분석은 중요하다.

의존관계 주입 3가지 1. 인터페이스에만 의존 2. 런타임시점 의존관계는 컨테이너와 팩토리 같은 제3의 존재가 결정 3. 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공해줌으로써 만들어짐

// 관계설정 분리 전의 생성자
public UserDao(){
  connectionMaker = new DConnectionMaker();
}

// 관계주입을 위한 코드
...
private ConnectionMaker connectionMaker; 
public UserDao(ConnectionMaker connectionMaker){ // 생성자DI
  this.connectionMaker = connectionMaker; 
}

7.3 의존관계 검색과 주입

의존관계 검색(LookUp) -> 오브젝트가 필요하는 곳에 자동으로 할당됨. 단, 자신의 구현체를 결정짓지는 못한다. 한번의 기동으로 인해 필요한 오브젝트들을 로딩시켜놔야 한다. 그래서 name 기반으로 검색이 가능하기 떄문. 의존관계 검색과 주입의 차이점 의존관계 검색인 경우, 검색하는 오브젝트 자신이 굳이 스프링 빈일 필요가 없다는 것. DI는 검색하는 오브젝트까지 스프링 빈이어야 한다.

그래서 어노테이션 기반일 때

@Repository나 @Component 같은걸 클래스에 붙이나보다..?

7.4 의존관계 주입의 응용

OCP 관점 !

  • 수정

    클래스 기반인 경우, 수정시 딱 한군데만 수정하면 모든 곳에 적용이 된다. 그리고 영향을 다른 곳에서 받지 않게 된다.

    // 수정 전
    @Bean
    public ConnectionMaker connectionMaker(){
      return new LocalDBConnectionMaker();
    }
    
    // 수정 후
    @Bean
    public ConnectionMaker connectionMaker(){
      return new ProductionDBConnectionMaker();
    }

    단 한줄 수정으로 위 connectionMaker 메서드를 사용하는 모든 곳에서 바로 적용 가능. 이것이 분리의 힘, DI의 편리함

  • 기능추가

    기능추가시에도 영향을 받지 않는다.

    ```java // 설정 클래스 @Configuration public class CountingDaoFactory {

@Bean
public UserDao userDao() {
  UserDao dao = new UserDao();
  dao.setConnectionMaker(connectionMaker());  // 변경사항
  return dao;
  //    return new UserDao(connectionMaker());
}

@Bean
public ConnectionMaker connectionMaker() {
  return new CountingConnectionMaker  (realConnectionMaker());  // 추가 됨
}

@Bean
public ConnectionMaker realConnectionMaker() {
  return new DConnectionMaker();  // 기존 커넥션 연결
}

}

// 추가 된 클래스 public class CountingConnectionMaker implements ConnectionMaker { int counter = 0; private ConnectionMaker connectionMaker;

public CountingConnectionMaker(ConnectionMaker connectionMaker) { this.connectionMaker = connectionMaker; }

@Override public Connection makeConnection() { this.counter++; return this.connectionMaker.makeConnection(); }

public int getCounter() { return counter; }

  - TEST
  ```java
  @Test
  public void test_1_32() {
    ApplicationContext context = new AnnotationConfigApplicationContext(CountingDaoFactory.class);
    UserDao userDao = context.getBean("userDao", UserDao.class);

    userDao.add(new User());
    userDao.get("S");

    CountingConnectionMaker maker = context.getBean("connectionMaker", CountingConnectionMaker.class);
    System.out.println("maker.getCounter() = " + maker.getCounter());
  }

7.5 메소드를 이용한 의존관계 주입

  • 수정자(setter)메서드 이용

    setAbc

    set으로 시작하고, set~다음 대문자로 시작해야함

    매개변수로 설정한 빈정보로 DI가 됨

    제약 : 1개의 파라미터만 받음

    • java

      // 세터 주입
      public void setConnectionMaker(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
      }
    • xml

      <bean id="connectionMaker" class="chap01_오브젝트와의존관계.DConnectionMaker"/>
      <bean id="userDao" class="chap01_오브젝트와의존관계.UserDao">
        <property name="connectionMaker" ref="connectionMaker"/>
      </bean>
  • 일반메서드 이용

    형식은 수정자 메서드와 동일

    차이는 1개이상의 파라미터 수용

    // TODO 차후 정리

8. XML을 이용한 설정

Spring에서 메타정보/설정정보를 정의하는 형식 1. 자바 2. XML 3. 자바 + XML

8.1 XML 설정

xml은 java코드에 비해 덜 유연하고, 속성의 값에 명시적인 설정이 필요

  • Bean의 이름 : @Bean

  • Bean의 클래스 : Bean 오브젝트

  • Bean의 의존 오브젝트 : Bean 생성자, setter메서드

connectionMaker() 전환

내용

자바 코드 설정정보

XML 설정정보

Bean 설정파일

@Configuration

<beans>

Bean 이름

@Bean 메서드명

<bean id="메서드명" class="">

Bean 클래스

return new BeanClass();

<bean id="" class="x.y.BeanClass"/>

  • <property>

    • name 속성 -> set메서드명으로 매핑

    • ref 속성 -> bean 설정 정보내에서 참조 (id기반으로 매핑, 객체 전달)

    • value 속성 -> 원시타입, 스트링값으로 주입됨 (값 전달)

  • XML 설정

    <bean id="connetionMaker" class="chap01_오브젝트와의존관계.DConnectionMaker"/>
    
    <!-- ref 객체 전달 -->
    <bean id="userDao" class="chap01_오브젝트와의존관계.UserDao">
      <property name="connectionMaker" ref="connetionMaker"/>
    </bean>
    
    <!-- value 값 전달 -->
    <bean id="userDao3" class="chap01_오브젝트와의존관계.UserDao">
      <property name="connectionMaker" value="chap01_오브젝트와의존관계.NConnectionMaker"/> <!-- String으로 인식하여 Error 발생-->
    </bean>

8.2 XML을 이용하는 애플리케이션 컨텍스트

XML 설정 클래스

  • GenericXmlApplicationContext (가장 많이 쓰임) : xml설정 정보 뿐 아니라 다양한 설정파일을 읽을 수 있음 : 파라미터 명 : resourceLocations

  • ClassPathXmlApplicationContext : xml에서 설정정보를 가져오는 애플리케이션 컨텍스트만 : 파라미터 명 : configLocation

  // GenericXmlApplicationContext -> 파라미터 명, 타입 확인(가변인자)
  public GenericXmlApplicationContext(String... resourceLocations) {
    this.load(resourceLocations);
    this.refresh();
  }

  // ClassPathXmlApplicationContext 생성자 -> 파라미터명 확인
  public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[]{configLocation}, true, (ApplicationContext)null);
  }
  • XML 설정으로 사용 예

    // 파라미터 -> xml 정보 
    // `/`가 없어도 루트로 시작
    @Test
    public void test_1_40() {
    
      // 2개의 xml파일에서 설정정보를 들고 올 수 있음
      // ApplicationContext context = new GenericXmlApplicationContext("chap01.ioc_di/applicationContext.xml", "chap01.ioc_di/chap01.xml");  
    
      ApplicationContext context = new GenericXmlApplicationContext("chap01.ioc_di/applicationContext.xml");    // 클래스패스에서 -> 파일경로(1개이상 파라미터로 가능)
      ApplicationContext context2 = new ClassPathXmlApplicationContext("chap01.ioc_di/applicationContext.xml"); // 클래스패스에서 -> 파일경로
      UserDao dao = context.getBean("userDao", UserDao.class);
      UserDao dao2 = context2.getBean("userDao", UserDao.class);
    
      System.out.println("dao = " + dao);
      System.out.println("dao2 = " + dao2);
    
    }

8.3 DataSource 인터페이스로 변환

ConnectionMaker는 사실 DataSource 인터페이스의 부분적 구현이다.

  • DataSource 인터페이스 적용

    • DB커넥션 -> 제공되는 인터페이스 적용 (JDBC 라이브러리 설정)

    • 구현클래스 -> SimpleDriverDataSource 주로 사용

    • 4가지 정보 : JDBC 드라이버클래스, URL, UserName, Password

  • 자바 코드

      @Bean
      public DataSource dataSource() {
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class);
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306");
        dataSource.setUrl("root");
        dataSource.setPassword("root");
        return dataSource; 
      }
    
      @Bean
      public UserDao userDao() {
        UserDao userDao = new UserDao();
        userDao.setDataSource(DataSource());  // DI (DB커넥션)
        return userDao; 
      }
  • xml

      <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <!-- 4가지 정보 필수 입력-->
        <!--    <property name="driverClass" value="${db.driver}"/>-->
        <!--    <property name="url" value="${db.url}"/>-->
        <!--    <property name="username" value="${db.name}"/>-->
        <!--    <property name="password" value="${db.password}"/>-->
      </bean>
    
      <bean id="userDao" class="chap01_오브젝트와의존관계.UserDao">
        <property name="dataSource" ref="dataSource"/>
      </bean>

8.4 프로퍼티 값의 주입

  • value 속성 (기본 String 값)

    <property name="abc" value="String 값"/>
  • 자동 타입 변환 (String -> Object)

    <!-- value 값 -> 적당한 타입으로 자동변환해줌  -->
    <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
  • 이외 자동 타입 변환 Integer, Double, String, Boolean / Class, URL, File, Charset... / List, Map, Set, Propeties, 배열

Last updated