스프링 퀵 스타트 Day 01

순서

  • 개발 환경 셋팅
  • Spring Overview
  • IoC, Dependency Injection
  • 실습 Day 01



개발 환경 셋팅

  1. JDK 1.8 설치
  2. H2 Database 설치
  3. Gradle Build Tool 설치
  4. IntelliJ IDEA 2017 설치
  5. Spring Initializer를 통한 실습 프로젝트 생성
    • XML 설정 프로젝트 생성 실습
    • Spring-boot 프로젝트 생성 실습



Spring Overview

왜 스프링인가?

스프링을 써서 개발하면 어플리케이션 개발을 빠르고 효율적으로 할 수 있도록

  • 어플리케이션의 바탕이 되는 틀
  • 공통 프로그래밍 모델과 기술 API

등을 제공해준다.

  • 어플리케이션의 기본 틀: 스프링 컨테이너
  • 공통 프로그래밍 모델: IoC/DI, 서비스 추상화, AOP
  • 기술 API: Spring MVC, Sprign JDBC

한 마디로 스프링을 써서 웹 어플리케이션을 개발하면 기본틀 위에서 개발하기 때문에 효율적인 코드 작성이 가능하다는 소리

스프링이 없을 땐 웹 어플리케이션을 어떻게 개발하고 운영했을까?

Java 환경에서 스프링이 없을 때는 아래와 같이 웹 어플리케이션 개발은 Java Servlet을 통해 개발을 했었다.

  1. Java Servlet Class 작성 (javax.servlet.http.HttpServlet을 상속받아 HTTP_METHOD별 처리 메소드를 만듬)
  2. web.xml 파일에 URI와 앞에서 만든 Servlet 클래스를 정의
  3. war로 패키징
  4. Tomcat의 webapp 폴더에 배포
  5. Tomcat 실행
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.skplanet.servlet.exercise.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
package com.skplanet.servlet.exercise;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletOutputStream outputStream = resp.getOutputStream();
        outputStream.write("Hello, world!".getBytes());
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // do something
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // do something
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // do something
    }
}

TV 제어 API를 개발한다고 치자.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    ...

    <servlet>
        <servlet-name>samsungTvServlet</servlet-name>
        <servlet-class>com.skplanet.servlet.exercise.SamsungTvServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>samsungTvServlet</servlet-name>
        <url-pattern>/samsung-tv</url-pattern>
    </servlet-mapping>
</web-app>

public interface Tv {
  public void powerOn();
  public void powerOff();
  public void volumeUp();
  public void volumeDown();
}

class SamsungTv implements Tv {
  public void powerOn() {
    System.out.println("SamsungTV -- 전원켠다.");
  }
  public void powerOff() {
    System.out.println("SamsungTV -- 전원끈다.");
  }
  public void volumeUp() {
    System.out.println("SamsungTV -- 소리올린다.");
  }
  public void volumeDown() {
    System.out.println("SamsungTV -- 소리내린다.");
  }
}

class LgTv implements Tv {
  public void powerOn() {
    System.out.println("LgTV -- 전원켠다.");
  }
  public void powerOff() {
    System.out.println("LgTV -- 전원끈다.");
  }
  public void volumeUp() {
    System.out.println("LgTV -- 소리올린다.");
  }
  public void volumeDown() {
    System.out.println("LgTV -- 소리내린다.");
  }
}
public class SamsungTvServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      SamsungTv tv = new SamsungTv();
      String action = req.getParameter("action");

      switch(action) {
        case "POWER_ON":
          tv.powerOn();
          break;
        case "POWER_OFF":
          tv.powerOff();
          break;
        case "VOLUME_UP":
          tv.volumeUp();
          break;
        case "VOLUME_DOWN":
          tv.volumeDown();
          break;
      }
    }
}
public class LgTvServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      LgTv tv = new LgTv();
      String action = req.getParameter("action");

      switch(action) {
        case "POWER_ON":
          tv.powerOn();
          break;
        case "POWER_OFF":
          tv.powerOff();
          break;
        case "VOLUME_UP":
          tv.volumeUp();
          break;
        case "VOLUME_DOWN":
          tv.volumeDown();
          break;
      }
    }
}

결합도를 낮추기 위해 디자인패턴을 적용해보자.
TV가 S사, L사는 쓸 수 없고 다른 회사의 제품으로 교체해야 된다고 했을 때 각 서블릿마다 들어가서 고쳐야 되는 것인가?

요구사항에 좀 더 유연하게 대응하기 위해서 Factory Method 패턴을 적용하자.

public class TvFactory {
  public Tv getTv(String tvName) {
    if (tvName.equals("samsung")) {
      return new SamsungTv();
    } else if (tName.equals("lg")) {
      return new LgTv();
    }
    return null;
  }
}
public class SamsungTvServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      TvFactory tvFactory = new TvFactory();
      Tv tv = tvFactory.getTv("samsung");
      String action = req.getParameter("action");

      switch(action) {
        case "POWER_ON":
          tv.powerOn();
          break;
        case "POWER_OFF":
          tv.powerOff();
          break;
        case "VOLUME_UP":
          tv.volumeUp();
          break;
        case "VOLUME_DOWN":
          tv.volumeDown();
          break;
      }
    }
}
public class LgTvServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      TvFactory tvFactory = new TvFactory();
      Tv tv = tvFactory.getTv("lg");
      String action = req.getParameter("action");

      switch(action) {
        case "POWER_ON":
          tv.powerOn();
          break;
        case "POWER_OFF":
          tv.powerOff();
          break;
        case "VOLUME_UP":
          tv.volumeUp();
          break;
        case "VOLUME_DOWN":
          tv.volumeDown();
          break;
      }
    }
}




IoC, Dependency Injection

IoC

Tv 인스턴스를 클라이언트(서블릿)에서 한게 아니라 Factory 클래스에게 요청하면 그 때서야 인스턴스를 반환하는 방식으로 변경이 되었는데,
이걸 제어의 역전(Inversion of Control, IoC)라고 부른다.

스프링의 핵심 기술 중 하나가 IoC를 전문적으로 해주는 IoC 컨테이너를 제공한다는 것이다.

public class SamsungTvServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      ApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
      Tv tv = (Tv) factory.getBean("samsung");
      String action = req.getParameter("action");

      switch(action) {
        case "POWER_ON":
          tv.powerOn();
          break;
        case "POWER_OFF":
          tv.powerOff();
          break;
        case "VOLUME_UP":
          tv.volumeUp();
          break;
        case "VOLUME_DOWN":
          tv.volumeDown();
          break;
      }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="samsungTv" class="com.skplanet.spring.plalab.SamsungTv"></bean>
    <bean id="lgTv" class="com.skplanet.spring.plalab.LgTv"></bean>
</beans>

Dependency Injection

이번엔 스피커를 추가하여 Tv 볼륨을 제어해보자.

public class SonySpeaker implements Speaker {
  public SonySpeaker() {
    System.out.println("===> Sony Speaker 객체 생성");
  }

  public void volumeUp() {
    System.out.println("Sony Speaker -- 소리 올린다.");
  }

  public void volumeDown() {
    System.out.println("Sony Speaker -- 소리 내린다.");
  }
}
public class SamsungTv implements Tv {
  private Speaker speaker;

  public SamsungTv(Speaker speaker) {
    this.speaker = speaker;
  }

  public void powerOn() {
    System.out.println("SamsungTV -- 전원켠다.");
  }
  public void powerOff() {
    System.out.println("SamsungTV -- 전원끈다.");
  }
  public void volumeUp() {
    this.speaker.volumeUp();
  }
  public void volumeDown() {
    this.speaker.volumeDown();
  }
}

예전 TvFactory를 사용한다면 Factory 클래스에서 인스턴스화 할 때 생성자로 넘겨(주입해)준다.

public class TvFactory {
  public Tv getTv(String tvName) {
    if (tvName.equals("samsung")) {
      Speaker speaker = new SonySpeaker();
      return new SamsungTv(speaker);
    } else if (tName.equals("lg")) {
      Speaker speaker = new SonySpeaker();
      return new LgTv(speaker);
    }
    return null;
  }
}

이와 같이 Tv에 의존관계(Dependency)가 있는 Speaker를 생성자로 주입(Injection)해 줬다고 해서 이를 Dependency Injection이라고 부른다.

이걸 스프링으로는 어떻게 할까?
XML로 직접 연결하거나, 어노테이션(@Autowired, @Resource)를 사용하여 알아서 주입되게 한다.

  1. XML을 통해 직접 Dependency Injection 정의하기

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="samsungTv" class="com.skplanet.spring.plalab.SamsungTv">
            <property name="speaker" ref="sonySpeaker"></property>
        </bean>
        <bean id="sonySpeaker" class="com.skplanet.spring.plalab.SonySpeaker">
        </bean>
    </beans>
  2. 자동으로 Dependency Injection 하기

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="com.skplanet.spring.plalab"/>
    </beans>
@Component
public class SonySpeaker implements Speaker {

  public SonySpeaker() {
    System.out.println("===> Sony Speaker 객체 생성");
  }

  public void volumeUp() {
    System.out.println("Sony Speaker -- 소리 올린다.");
  }

  public void volumeDown() {
    System.out.println("Sony Speaker -- 소리 내린다.");
  }
}
@Component
public class SamsungTv implements Tv {

  @Autowired
  private Speaker speaker;

  public void powerOn() {
    System.out.println("SamsungTV -- 전원켠다.");
  }
  public void powerOff() {
    System.out.println("SamsungTV -- 전원끈다.");
  }
  public void volumeUp() {
    this.speaker.volumeUp();
  }
  public void volumeDown() {
    this.speaker.volumeDown();
  }
}

실습 Day 01

Page 109 ~ 139

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2019 Icednut's Note All Rights Reserved.

Icednut hold copyright