[Spring] 스프링으로 계산기 만들기

2023. 9. 22. 03:22학부 강의/웹프로그래밍 (Spring)

0. 출처

아직 배우고 있는 중이라 부정확한 정보가 포함되어 있을 수 있습니다!
주의하세요!

 

올인원 스프링 프레임워크 참고.

 

올인원 스프링 프레임워크 : 네이버 도서

네이버 도서 상세정보를 제공합니다.

search.shopping.naver.com

 


1.디렉터리 구조

 

  • [project_name]/src/main/java : .java 파일 관리.
  • [project_name]/src/main/resources : 자원 관리. 스프링 설정 파일(xml) 또는 프로퍼티 파일.
  • pom.xml : 메이븐 설정 파일

 

 


가. 메인 리포지터리

 

또는 remote repository라고 한다.

 

필요한 모듈들을 다운로드하는 곳이다.

 

https://mvnrepository.com이 우리가 사용하는 메인 리포지터리의 주소다.

 

 

다운로드하여서 사용할 수 있는 다양한 Artifact(모듈)들이 있다.

 

pom.xml을 통해서 모듈을 다운로드할 수 있다.

 

apache 재단에서 관리한다. (maven이 apache 재단에서 호스팅 한다.)

 


나. 로컬 리포지터리

 

메인 리포지터리에서 다운로드한 라이브러리(.jar)가 설치되는 디렉터리.

//default location of local repository
${user. home}/. m2/repository/

//윈도우의 로컬 리포지터리 경로
C:\Users\<User_Name>\.m2\repository\

//리눅스의 로컬 리포지터리 경로
/home/<User_Name>/.m2
//또는
~/.m2

//맥의 로컬 리포지터리 경로
/Users/<user_name>/.m2
//또는
~/.m2

한 번 설치한 모듈은 재사용된다.

 

 


다. 프로젝트 빌드 설정

<!-- pom.xml -->
...
<!-- bulid config -->
  <build>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.11.0</version>
              <configuration>
                  <source>11</source>
                  <target>11</target>
                  <encoding>utf-8</encoding>
              </configuration>
          </plugin>
      </plugins>
  </build>
  • <source>11</source> : java 소스 코드의 버전. 여기선 java 11의 문법과 API를 사용하여 코드를 컴파일함.
  • <target>11</target> : 바이트 코드의 버전을 의미함. 여기선 java 11 버전의 JVM에서 실행될 것임을 의미한다.
  • <encoding>utf-8</encoding> : 소스 코드의 인코딩 설정. Maven 컴파일러가 소스 코드를 읽을 때 utf-8로 읽도록 지시함.

 


2. 스프링으로 계산기 만들기

 

가. MainClass.java

package ch03_calc_01;
import org.springframework.context.support.GenericXmlApplicationContext;

public class MainClass {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");

        CalAssembler calAssembler = ctx.getBean("calAssembler", CalAssembler.class);
        calAssembler.assembler();

        ctx.close();
    }

}

IoC 컨테이너에서부터 calAssembler bean을 받아온다.

 

이때 가져올 뿐 calAssembler bean을 가져오기 위해서 어떠한 값도 전달하지 않는다.

 


나. CalAssembler.java

package ch03_calc_01;

public class CalAssembler {

    MyCalculator calculator;
    CalAdd calAdd;
    CalSub calSub;
    CalMul calMul;
    CalDiv calDiv;

    public CalAssembler(MyCalculator calculator, CalAdd calAdd, CalSub calSub, CalMul calMul, CalDiv calDiv) {
        this.calculator = calculator;
        this.calAdd = calAdd;
        this.calSub = calSub;
        this.calMul = calMul;
        this.calDiv = calDiv;
    }

    public void assembler() {
        calculator.calculate(10,5,calAdd);
        calculator.calculate(10,5,calSub);
        calculator.calculate(10,5,calMul);
        calculator.calculate(10,5,calDiv);
    }
}

스프링 사용 이전과 비교해 보자.

 

//스프링 사용 이전
    public CalAssembler(){
        calculator = new MyCalculator();
        calAdd = new CalAdd();
        calSub = new CalSub();
        calMul = new CalMul();
        calDiv = new CalDiv();

        assemble();
    }

CalAssembler의 생성자에서 더 이상 MyCalculator, CalAdd, CalSub, CalMul, CalDiv 객체를 생성하지 않는다.

 

하지만 앞선 MainClass에서도 CalAssembler를 사용할 때 MyCalculator, CalAdd, CalSub, CalMul, CalDiv을 전달해주지 않았다.

 

그러면 언제, 누가 MyCalculator, CalAdd, CalSub, CalMul, CalDiv를 전달해 주었을까?

 


다. applicationContext.xml

<!-- applicationContext.xml -->
<?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="tWalk" class="ch03_pjt_02.TransportationWalk" /> -->
    <bean id="cAdd" class="ch03_calc_01.CalAdd" />
    <bean id="cSub" class="ch03_calc_01.CalSub" />
    <bean id="cMul" class="ch03_calc_01.CalMul" />
    <bean id="cDiv" class="ch03_calc_01.CalDiv" />

    <bean id="myCalculator" class="ch03_calc_01.MyCalculator" />

    <bean id="calAssembler" class="ch03_calc_01.CalAssembler" >
        <constructor-arg ref="myCalculator"/>
        <constructor-arg ref="cAdd" />
        <constructor-arg ref="cSub" />
        <constructor-arg ref="cMul" />
        <constructor-arg ref="cDiv" />
    </bean>
</beans>

beans를 추가한다.

 

이때 CalAssembler처럼 생성자에 매개변수가 있는 경우를 살펴보자.

 

<bean id="calAssembler" class="ch03_calc_01.CalAssembler" >
    <constructor-arg ref="myCalculator"/>
    <constructor-arg ref="cAdd" />
    <constructor-arg ref="cSub" />
    <constructor-arg ref="cMul" />
    <constructor-arg ref="cDiv" />
</bean>

calAssebler bean과 CalAssember Class의 생성자를 비교해 보자.

 

public CalAssembler(MyCalculator calculator, CalAdd calAdd, CalSub calSub, CalMul calMul, CalDiv calDiv){...}

CalAssember의 생성에 필요한 인자를 순서대로 calAssebler bean에 <constructor-arg>로 추가하면 된다.

 

물론 구체적으로 지정하는 방법도 있다.

 

constructor-arg 의 속성을 사용하면 된다. (아래에서 설명함. 다-2 참고)

 

이렇게 IoC 컨테이너에서 bean의 생성에 필요한 인자까지 자동으로 전달, 관리해 준다.

 

때문에 개발자는 applicationContext.xml에만 작성하면 다음부터는 편하게 사용할 수 있다.

 

 

생성자가 오버로딩 되어있다면 어떻게 되는 걸까?

 


1) 생성자만큼 bean 추가하기

 

만약에 CalAssembler에 첫 번째 인자로 MyCalculator를, 두 번째 인자로 CalAdd를 받는 생성자가 있다고 가정하자.

    public CalAssembler(MyCalculator calculator, CalAdd calAdd, CalSub calSub, CalMul calMul, CalDiv calDiv) {
        this.calculator = calculator;
        this.calAdd = calAdd;
        this.calSub = calSub;
        this.calMul = calMul;
        this.calDiv = calDiv;
    }

    public CalAssembler(MyCalculator calculator, CalAdd calAdd) {
        this.calculator = calculator;
        this.calAdd = calAdd;
    }

이때 CalAssembler를 bean으로 추가하기 위해선 어떻게 해야 할까?

 

첫 번째 방법은 생성자 수만큼 applicationContext에 추가하는 것이다.

 

<!-- 첫 번째 생성자를 사용하는 CalAssembler bean 정의 -->
    <bean id="calAssemblerFull" class="ch03_calc_01.CalAssembler" >
        <constructor-arg ref="myCalculator"/>
        <constructor-arg ref="cAdd" />
        <constructor-arg ref="cSub" />
        <constructor-arg ref="cMul" />
        <constructor-arg ref="cDiv" />
    </bean>

    <!-- 두 번째 생성자를 사용하는 CalAssembler bean 정의 -->
    <bean id="calAssemblerPartial" class="ch03_calc_01.CalAssembler" >
        <constructor-arg ref="myCalculator"/>
        <constructor-arg ref="cAdd" />
    </bean>

Spring는 기본적으로 bean을 Singleton으로 생성한다. (트래픽마다 계속 객체를 생성하게 되면 메모리 낭비가 심하기 때문)

 

Spring Container 내에서 한 번 생성된 bean 객체를 재사용하는 것을 의미한다.

 

다만 생성자만큼 bean을 따로 등록하게 되면 생성되는 bean의 객체는 그만큼 늘어난다.

 

출처 : https://velog.io/@gojaebeom/XML으로-Bean-등록하기

 


2) constructor-arg의 속성 이용하기

 

 

constructor-arg 태그는 bean의 생성자 인자를 정의할 때 사용된다.

 

public class Example {
    public Example(String a) {
        //...
    }

    public Example(String a, int b) {
        //...
    }

    public Example(int b, String c) {
        //...
    }
}
<bean id="exampleBean1" class="path.to.Example">
    <constructor-arg index="0" value="SomeString"/>
    <constructor-arg index="1" value="5"/>
</bean>

<bean id="exampleBean2" class="path.to.Example">
    <constructor-arg index="0" value="5"/>
    <constructor-arg index="1" value="SomeString"/>
</bean>

이러한 속성들을 조합하여 생성자 인자를 명확하게 지정하면 여러 개 오버로딩된 생성자도 처리가능하다.

 

참.고.로.

<!-- 에러 발생 -->
<bean id="exampleBean3" class="path.to.Example">
    <constructor-arg name="a" value="SomeString"/>
    <constructor-arg name="b" value="5"/>
    <constructor-arg name="c" value="SomeString"/>
</bean>

위와 같은 방식으로 하나만으로 모든 생성자를 커버할 수 있지 않을까 생각해 봤다.

 

하지만 안된다고 한다.

 

Example 클래스에는 최대 두 개의 매개변수만을 받는 생성자들만 정의되어 있다.

 

name 속성을 활용해서도 세 개의 인자를 받는 생성자가 없기 때문에 Example 클래스의 적절한 생성자를 찾을 수 없으므로 오류를 발생시킨다.

 

그러니 상황에 따라 하나의 bean으로 모든 생성자를 커버 치지 못할 수 있다.

 


라. 나머지

더보기
package ch03_calc_01;

public class MyCalculator {
	public void calculate(int fNum, int sNum, ICalculator calculator) {
		int value = calculator.doOperation(fNum, sNum);
		System.out.println("result : " + value);
	}
}
  package ch03_calc_01;

  public class CalAdd implements ICalculator {
      @Override
      public int doOperation(int fNum, int sNum) {
          // TODO Auto-generated method stub
          return fNum + sNum;
      }

  }
  package ch03_calc_01;

  public class CalSub implements ICalculator {
      @Override
      public int doOperation(int fNum, int sNum) {
          // TODO Auto-generated method stub
          return fNum - sNum;
      }

  }
  package ch03_calc_01;

  public class CalMul implements ICalculator {
      @Override
      public int doOperation(int fNum, int sNum) {
          // TODO Auto-generated method stub
          return fNum * sNum;
      }

  }
  package ch03_calc_01;

  public class CalDiv implements ICalculator {
      @Override
      public int doOperation(int fNum, int sNum) {
          // TODO Auto-generated method stub
          return sNum !=0 ? (fNum + sNum) : 0;
      }

  }

 


 

'학부 강의 > 웹프로그래밍 (Spring)' 카테고리의 다른 글

[Spring] Spring Bean Scope  (0) 2023.10.07
[Spring] 학사 정보 시스템  (0) 2023.10.07
[Spring] Maven  (0) 2023.09.14
[Spring] DI, DIP, IoC  (0) 2023.09.09
[Spring] 개발 환경 구축  (0) 2023.09.07