티스토리 뷰

3) xml파일을 이용한 설정

Maven으로 Java프로젝트 만들기

  • 프로젝트 - Maven Project를 생성합니다.
 
  • Archetype을 선택합니다.
    Maven 
    프로젝트에서 제공해주는 템플릿을 의미합니다. 어떤 것을 지정하느냐에 따라서 프로젝트 구조가 달라질 것이고 예제 등이 들어있을 수 있습니다.
  • 기업 같은 경우는 자신들만의 Archetype을 만들어서 사용할 수도 있겠죠.
  • 이번 시간에는 maven-archetype-quickstart 라는 것을 이용해서 만들어보겠습니다.
  • Group Id Artifact Id를 만들어주시면 됩니다. 보통 Group Id는 회사의 도메인을 거꾸로 쓴다고 했죠? 패키지 만드는 규칙하고 비슷하다고 생각하시면 되는데 나중에 Group Id Artifact Id가 패키지가 될 겁니다. 그래서 이런 규칙들을 지켜주시고 소문자로 사용하시는 게 좋습니다.
  • Artifact Id는 실제 프로젝트 이름을 적어주시면 돼요. 웹 애플리케이션 만들 때 firstWeb, 이거 프로젝트 이름이었죠? 그런 의미다고 생각을 하시면 됩니다. 이번엔 diexam01로 진행하겠습니다.

 

  • pom.xml 파일에 JDK를 사용하기 위한 플러그인 설정을 추가합니다.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>kr.or.connect</groupId>
  <artifactId>diexam01</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>diexam01</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
-------------------------------------추가----------------------------------------------------
  <build>
     <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
  </build>
----------------------------------------------------------------------------------------------

</project>

 

 

  • Problems에 떠있는 오류를 확인하고 메이븐 업데이트를 실행합니다.
  • 프로젝트를 선택하고, Maven -> Update Project를 선택합니다.
  • 창이 뜨면 OK를 누릅니다.
  • Properties → Java Compiler에서 jdk 1.8인지 확인합니다.
  • project explorer를 보면 src/main/Java라는 폴더가 자동으로 생성되어 있습니다. 그 안에는 아까 Group Id, Artifact Id로 넣었던 부분이 패키지 이름으로 만들어져서 나와있는 것을 확인할 수가 있습니다. 그리고 이 폴더 안에 App.java라는 클래스가 하나 만들어져 있는 거를 볼 수가 있습니다.
  • 열어보면 main 안에 hello world가 있는 것을 알 수 있습니다.

  • 다시 하단에 보시면 src/test/Java 하고 되어있는데 이 안에는 AppTest라는 클래스가 자동으로 만들어져 있는 것을 확인할 수가 있습니다.
  • AppTest TestCase라는 것을 상속받고 있습니다. 그리고 junit.famework.Test import 되어있는데요. 단위 테스트할 수 있는 도구입니다.
  • 모든 프로그램은 테스트가 굉장히 중요합니다. junit은 단위 테스트할 수 있는 도구로 가장 많이 사용되고 있는 프레임워크입니다.

  • Hello World가 잘 실행되는지 테스트해보려면 junit AppTest.java를 오른쪽 버튼 클릭하시고 Run As → Junit Test라는 메뉴가 실행하면 됩니다.
  • 실행해 보면 하단에 초록색 바가 하나 뜰 거예요. 초록색 바는 이 프로젝트가 지금 제대로 동작되고 있다는 걸 의미합니다.

 

  • 이 부분까지가 간단하게 Maven으로 프로젝트를 하나 만들어보는 과정을 수행한 것입니다.

 

App.java

package kr.or.connect.diexam01;

 

/**

 * Hello world!

 *

 */

public class App

{

    public static void main( String[] args )

    {

        System.out.println( "Hello World!" );

    }

}

 

AppTest.java

package kr.or.connect.diexam01;

 

import junit.framework.Test;

import junit.framework.TestCase;

import junit.framework.TestSuite;

 

/**

 * Unit test for simple App.

 */

public class AppTest

    extends TestCase

{

    /**

     * Create the test case

     *

     * @param testName name of the test case

     */

    public AppTest( String testName )

    {

        super( testName );

    }

 

    /**

     * @return the suite of tests being tested

     */

    public static Test suite()

    {

        return new TestSuite( AppTest.class );

    }

 

    /**

     * Rigourous Test :-)

     */

    public void testApp()

    {

        assertTrue( true );

    }

}

 

Bean class?

  • 예전에는 Visual한 컴포넌트를 Bean이라고 불렀지만, 근래 들어서는 일반적인 Java클래스를 Bean클래스라고 보통 말합니다.
  • Bean클래스의 3가지 특징은 다음과 같습니다.
    1. 기본생성자를 가지고 있습니다.
    2. 필드는 private하게 선언합니다.
    3. getter, setter 메소드를 가집니다.
      getName() setName()
      메소드를 name 프로퍼티(property)라고 합니다. (용어 중요)
  • 아래의 UserBean이라는 클래스는 생성하는 것을 사용자가 직접 하는 것이 아니라 컨테이너에 맡길 겁니다. 항상 기억해야 될 것은 내가 직접 하는 게 아니라 누군가가 대신 뭔가를 해줘야 되는데 이 때는 반드시 규칙들이 있어야 합니다.
  • 그리고 한가지 더, 실제 이 클래스에 각각의 필드에 접근해서 일을 해야 될 텐데 다 private 하잖아요. 객체지향 프로그래밍에서 이 객체의 속성에 직접 접근하는 거는 별로 바람직하지 않다고 생각하기 때문에 항상 메서드(여기서는 게터, 세터)를 통해서 접근을 하시는 게 좋습니다.
  • UserBean을 만들면 이 클래스를 Spring이 가진 공장이 만들어내게 해야합니다아무리 공장이 자동으로 한다고 해도 반드시 여러분이 알려줘야 될 정보는 알려줘야 된다는 것을 기억해야 합니다.

 

  • UserBean src/java/main의 기존 패키지에 생성합니다.

UserBean.java

package kr.or.connect.diexam01;

 

//빈클래스

public class UserBean {

          

           //필드는 private

           private String name;

           private int age;

           private boolean male;

          

           //기본생성자를 반드시 가지고 있어야 한다.

           public UserBean() {

           }

          

           public UserBean(String name, int age, boolean male) { //객체를 편하게 생성하기 위함.

                      this.name = name;

                      this.age = age;

                      this.male = male;

           }

 

           // setter, getter메소드는 프로퍼티라고 한다.

           public void setName(String name) {

                      this.name = name;

           }

 

           public String getName() {

                      return name;

           }

 

           public int getAge() {

                      return age;

           }

 

           public void setAge(int age) {

                      this.age = age;

           }

 

           public boolean isMale() {

                      return male;

           }

 

           public void setMale(boolean male) {

                      this.male = male;

           }

 

}

 

 

Spring Bean Factory를 이용하여 Bean객체 이용하기

  • 이 예제에서는 Spring bean 팩토리를 이용해서 bean을 생성합니다. 그렇게 하기 위해서는 Spring을 이용해야 합니다. Spring을 이용하시려면 Spring 라이브러리들이 필요할텐데 현재 우리는 Maven을 이용하기 때문에 Maven에다가 dependency 정보만 알려주면 될 거예요.
  • 일단 properties 태그에다가 이런 설정을 하나 넣어줍니다.
    <spring.version> 4.3.14.RELEASE</spring.version>
  • 위의 설정들은 상수처럼 사용할 수 있는 것입니다. dependency pom.xml 안에서 해당 값들이 자주 필요한 경우가 있습니다. 그럴 때 값 자체로 그냥 사용하는 게 아니라 spring.version이라는 이름으로 상수로 사용할 수 있도록 도와주는 거라고 생각하시면 됩니다.
  • 이제 Spring 라이브러리를 추가합니다. 사용할 Spring에 관련된 dependency를 추가하시면 됩니다. 여기서는 spring공장이 필요하므로 maven repository 사이트에서 spring context를 검색하여 4. 대 중 가장 최신버전 dependency를 복붙하면 됩니다. 여기선 4.3.14를 씁니다.

  • 이런 부분이 maven에서 편한 부분입니다. 왜냐하면 라이브러리를 하나씩 다 찾아서 여러분이 lib 디렉터리에다가 직접 넣고 사용하는 것은 매우 불편하기 때문입니다.
  • properties에서 설정한 spring.version${spring.version}과 같이 사용합니다. 이를 쓰는 이유는 여러 spring 기능들을 사용할 때 모든 것들에 대하여 버전을 통일시켜 변경하기 쉽게 하기 위함입니다.

1) pom.xml 파일을 다음과 같이 수정합니다.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>kr.or.connect</groupId>
  <artifactId>diexam01</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>diexam01</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version> 4.3.14.RELEASE</spring.version>
  </properties>

  <dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
  
  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
  <build>
     <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
  </build>
</project>

 

 

  • 저장 후에 maven dependencies를 보시면 context이외에 여러가지가 있는 것을 볼 수 있습니다.
  • 이는 Spring context가 다른 것들을 상속받거나 이런 관계를 갖고 있는 것들까지, Spring context가 관련 맡고 있는 라이브러리들도 제대로 실행하기 위해 다 같이 알아서 받아옵니다.

 

2) 추가된 라이브러리 확인합니다.

  • 여기까지 한 일은 Spring 공장을 추가한 것입니다. 이제 해야 될 일은 뭐냐면 이 Spring 공장한테 UserBean에 대한 정보를 알려줘야 합니다.

3) resources 소스 폴더를 생성합니다.

  • diexam01 프로젝트에 폴더를 하나 만듭니다. src/main에다가 리소스를 저장할 폴더를 resources라는 이름으로 만듭니다.
  • 프로젝트를 선택하고, 오른쪽 버튼을 클릭한 후 New -> Folder를 선택합니다.
  • src/main 폴더를 선택한 후 forder name resources라고 Finish버튼을 클릭합니다.
  • Spring한테 생성할 객체에 대한 정보를 줘야 되는 파일들이 필요할 텐데 소스랑 자바 파일이랑 섞여 있으면 복잡하므로 따로 관리해주기 위한 폴더를 하나 만든 겁니다.
  • 꼭 분리하지 않아도 상관은 없지만 설정 파일이 자바 폴더에 들어있어도 상관없겠지만 나중에 관리하기가 힘들어지므로 따로 만들어서 사용하는 것이 훨씬 깔끔하게 잘 관리할 수 있습니다.
  • resources안에 xml파일을 하나 만듭니다. 가장 많이 쓰이는 applicationContext.xml이라는 이름으로 생성합니다. application context들에게 설정들을 알려주겠다라는 의미를 갖고 있습니다.

 

 

<?xml version="1.0" encoding="UTF-8"?>
  • 이제 xml 파일에다가 정보를 작성합니다.
  • 첫 부분에 반드시 이 파일이 xml파일이고, 버전은 뭐고, 캐릭터 셋은 뭘 쓸 건지 이런 정보를 입력합니다.
http://www.springframework.org/schema/beans"</beans xmlns=" 
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"> 
  ...
</beans> 
  • xml 파일로 Spring 설정 파일을 만들게 되면 가장 바깥쪽 태그, 이것을 루트 element라고 합니다.
  • 반드시 applicationContext.xml의 루트 element는 beans로 설정해야 합니다.
  • 그리고 xml 스키마에 대한 설정도 되어있어야 합니다. 해당 설정 파일은 Spring 컨테이너가 읽어 들이는데 beans 태그 안에 아무것도 없으면 아무 일도 하지 않습니다.
<bean id="userBean" class="kr.or.connect.diexam01.UserBean"></bean>
  • Spring 컨테이너한테 내가 사용할 객체를 대신 생성하게 하기 위해 정보를 입력합니다. 이때 사용되는 element bean이라는 element입니다. 그리고 해당 element에다가 몇 가지 속성을 부여합니다.
  • 일단 id = "userBean" 이라고 id를 설정합니다beans id는 객체 생성시에 부여하는 레퍼런스 변수명과 같다고 보면 됩니다.
  • 그리고 클래스를 지정하는데 클래스는 내가 진짜 만들고 싶은 클래스를 의미합니다. 여기서는
    kr.or.connect.diexam01.UserBean 클래스를 등록했는데 저렇게 bean을 등록했다는 건 Spring이 나중에 객체를 생성하는 거랑 같은 의미다라고 보면 됩니다.
    kr.or.connect.diexam01.UserBean userBean = new kr.or.connect.diexam01.UserBean(); 
    이렇게 생각하시면 돼요. 정확히 알려주기 위해 반드시 패키지명까지 적어줍니다.

 

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="userBean" class="kr.or.connect.diexam01.UserBean"></bean>

</beans>

 

  • Spring 컨테이너는 이런 객체를 하나만 생성해서 가지고 있어요. 이렇게 객체를 딱 하나만 가지고 있는 것을 싱글턴 패턴이라고 합니다.
  • 이렇게 Spring 설정 파일을 작성했으니까 해당 설정 파일을 읽어들이는 객체도 하나 생성을 해야겠죠.
  • src/main/java의 패키지에 ApplicationContextExam01 클래스를 생성합니다. 이 클래스는 이 프로그램을 시작시킬 시작점 역할을 하게 됩니다. 그래서 main 메서드가 필요합니다.
  • 그리고 spring이 가진 공장을 생성합니다. spring 공장 중 ApplicationContext라는 공장을 사용합니다. ApplicationContext는 실제로 인터페이스라서 ApplicationContext를 구현하고 있는 객체들 중에 ClassPathXmlApplicationContext라는 객체를 사용해서 bean을 가져오려 합니다.
  • 인자에 classpath:applicationContext.xml이라는 문자열을 넣어 Bean정보를 알려줍니다. 그러니까 xml파일을 읽어서 bean 정보를 읽고 공장을 세울 수 있도록 알려줍니다.
  • 생성한 다음 라인에 sysout을 뿌려 동작이 잘 하는지 확인합니다잘 가져왔다는 가정하에 이제 공장을 이용하여 객체 정보를 얻어오면 됩니다. UserBean에 대한 레퍼런스 변수를 선언합니다. 그러나 실제로 생성은 내가 하지 않습니다. 공장한테 getBean()이라는 메서드를 이용하여 UserBean의 정보를 얻어냅니다. 이때 getBean()의 리턴값은 object이므로 형변환이 필요합니다.
  • 이제 getBean()에다가 "userBean"이라는 String을 보냈으니 공장은 해당 xml에서 id가 인자값이랑 일치하는 것이 있는지를 찾을 겁니다. 그리고 찾으면 등록되어있는 해당 클래스 이름을 알아낸 뒤 클래스를 생성합니다. 그런 다음에 생성한 클래스를 리턴할 것입니다. 즉, getBean()이라는 메서드가 해당 작업을 수행하는 것입니다.
  • Bean을 하나 얻어왔을 겁니다. 얻어온 bean에다가 세터를 사용합니다. userBean.setName(“kang”); 그런 다음에 제대로 들어갔는지 게터를 통해 확인합니다.
  • 이번에는 객체를 하나 더 얻어내보겠습니다. userBean2라는 이름으로 아까와 동일하게 코딩합니다. 그리고 if문을 사용하여 같은지 확인해보겠습니다.
  • 실행하면 같다고 나옵니다. 왜냐면 싱글턴을 이용했기 때문입니다. 그러니까 사용자가 계속 getBean() 해서 요청을 한다고 하더라도 그 객체를 계속 만들어내는 게 아니라 하나 만든 bean을 이용하는 거다라고 생각하시면 될 것 같습니다.

ApplicationContextExam01.java

package kr.or.connect.diexam01;

 

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

public class ApplicationContextExam01 {

 

           public static void main(String[] args) {

                      ApplicationContext ac = new ClassPathXmlApplicationContext(

                                             "classpath:applicationContext.xml");

                      System.out.println("초기화 완료.");

                     

                      UserBean userBean = (UserBean)ac.getBean("userBean");

                      userBean.setName("kang");

                      System.out.println(userBean.getName());

                     

                      UserBean userBean2 = (UserBean)ac.getBean("userBean");

                      if(userBean == userBean2) {

                                  System.out.println("같은 인스턴스이다.");

                      }

                     

           }

}

 

  • 잠깐 정리하면서 설명해보겠습니다.
  • ApplicationContext는 인터페이스입니다. 그렇다는 것은 ApplicationContext을 구현하는 다양한 컨테이너가 존재할 것이고 그 중에서 이런 xml 파일을 classpath에서 읽어들여서 사용하는 객체가 바로 ClassPathXmlApplicationContext 입니.
  • main의 resources 폴더는 소스폴더이며 이 폴더에서 생성한 설정파일, xml은 자동으로 classpath로 지정이 됩니다. Java 디렉터리에서 만들어진 클래스들과 마찬가지로 bean 디렉터리에 생성되어 있을 거다는 거 알고 계시면 되겠고 그렇기 때문에 ClassPathXmlApplicationContext로 읽어서 사용할 수가 있다고 이해하시면 됩니다.
  • ClassPathXmlApplicationContext 인스턴스가 생성될 때 생성자 파라미터로 지정된 설정 파일을 읽어들인 후에 그 안에 선언된 bean들을 모두 메모리에 올려줄 겁니다. 만약 applicationContext.xml 파일에 등록한 bean들이 여러 개가 있다면 그 bean들의 정보를 다 읽어들여가지고 설정되어 있는 객체들을 전부 생성해서 메모리에다가 올려놓아요. 만약 이때 문제가 발생하면 해당 애플리케이션은 종료가 됩니다.
  • ApplicationContext가 가지고 있는 getBean()이라는 메서드가 존재하죠. getBean() 메서드의 파라미터로 xml의 설정에다가 적어놓았던 id 값을 넣어주면 해당 객체의 레퍼런스가 반환이 됩니다. 이런 Spring 설정 파일의 객체들은, Spring이 제공하는 공장이 만들어내는 객체들은 다양한 객체를 생성할 수가 있어요. 그래서 getBean()은 object 타입으로 리턴을 하게 됩니다. 필요에 따라서 형변환을 해야 사용할 수 있습니다.
  • id를 파라미터로 넘겨 등록돼 있는 userBean을 얻어내서 얻어낸 bean한테 setter를 통해 값을 설정하고 getter를 통해 값을 얻어 올 수 있습니다.
  • 그리고 getBean()으로 등록되어 있는 동일한 id로 객체를 2개 만들어 보면 처음에 얻은 userBean 객체랑 두 번째 요청해서 얻은 userBean 객체랑 같은 객체라는 것을 알 수 있었습니다. bean 공장이 싱글턴 패턴을 이용해서 bean들을 생성하기 때문에 같은 객체라는 것을 알 수 있었습니다.
  • 이렇게 객체를 대신 생성해주고 싱글턴으로 관리해주는 기능 등을 IOC 제어의 역전이라고 합니다.

DI 확인하기

  • 이번에는 DI 즉 의존성 주입을 확인해보도록 하겠습니다.
  • Car Engine이라는 클래스 2개를 src/main/java의 패키지에 생성합니다.
//////////Engine.java//////////

package kr.or.connect.diexam01;

 

public class Engine {

           public Engine() {

                      System.out.println("Engine 생성자");

           }

          

           public void exec() {

                      System.out.println("엔진이 동작합니다.");

           }

}

  • Engine 클래스에는 기본 생성자와 exec()라는 메서드를 하나 가지고 있습니다.
//////////Car.java///////////

package kr.or.connect.diexam01;

 

public class Car {

           Engine v8;

          

           public Car() {

                      System.out.println("Car 생성자");

           }

          

           public void setEngine(Engine e) {

                      this.v8 = e;

           }

          

           public void run() {

                      System.out.println("엔진을 이용하여 달립니다.");

                      v8.exec();

           }

}

  • Car 클래스는 필드로 엔진을 하나 가지고 있어요. 이 엔진의 이름은 v8이라고 하겠습니다.
  • 그리고 default 생성자를 하나 가지고 있는데 객체가 생성됐을 때 언제 생성이 되는지 이런 부분들을 확인해보기 위해서 생성자 부분에다가 메시지를 하나 추가시켜 보겠습니다.
  • Car 클래스는 두 가지 메서드를 가지고 있습니다.
  • 하나는 setEngine()이라는 메서드입니다. 메서드가 실행될 때 Engine 타입의 엔진을 하나 받아와가지고 Car의 엔진인 v8에다가 받아온 엔진을 넣어주는 메서드입니다.
  • 다른 하나는 자동차가 달릴 때 사용하는 run()이라는 메서드입니다. 언제 달리는지 알아야 되니까 콘솔에 메시지를 띄우도록 합니다. 그리고 실제로 달리는건 엔진이 달리는 것입니다. 엔진(v8)이 가지고 있는 exec() 메서드를 실행하고자 합니다.

//////////main/////////////

Engine e = new Engine();

Car c = new Car();

c.setEngine( e );

c.run();

실제 Car라는 자동차 클래스가 제대로 동작하려면 어떤 코드가 있어야 할까요? 자동차는 엔진이 필요하니까 일단 Engine 클래스가 하나 생성이 되어야 합니다.

다음에는 자동차가 만들어질 거예요. 그리고 자동차가 갖고 있는 setEngine() 메서드에다가 먼저 생성된 엔진을 넣어주면 되겠죠. 그런 다음에 자동차한테 달리라고 실행하면 엔진이 생성됐고, 자동차가 생성됐고 다음은 엔진은 이용해서 달리고 엔진이 동작합니다.

 

  • 개발자가 직접 객체를 생성한다면 이런 순서대로 만들어져야 합니다. 그러나 이제는 이런 것을 직접 만드는 것이 아니라 배운대로 객체를 생성하고 있는 부분을 제어의 역전으로 넘겨야 합니다. 그러니까 이렇게 객체가 생성이 되어야 하는 것을 Spring IoC 컨테이너가 만들도록 해야 합니다.
  • 이런 과정을 Spring 컨테이너가 하게 하려면 설정 파일에다가 해당 Bean들을 등록해야 합니다.
  • 그 부분을 수행하게 하기 위해서 resources 폴더 안에 있는 applicationConfig.xml 파일에다가 bean을 하나 등록해보도록 합니다.
  • 엔진을 'e'라고 만들었었으니까 id'e'하시면 될 것 같고요. 그런 다음에 class를 패키지의 Engine이라는 클래스를 정의해주면 됩니다. 자동차 Car 객체도 똑같이 등록을 하시면 됩니다. idc로 하고 클래스를 적어서 등록합니다.
  • 이렇게 하면 Engine Car의 인스턴스가 싱글턴으로 생성이 될 겁니다. 하지만 xml에서 Car에다가 Engine Set 하라는 의미의 코드가 존재하지 않습니다. Car 인스턴스의 엔진을 Set 하기 위해 해당 bean의 <bean></bean> 사이에 property라고 하는 element를 사용할 수 있습니다. bean의 getter, setter를 프로퍼티라고 합니다.
  • <property> name에다가 name="engine"이라고 할 거고요. 그 뒤에 ref를 적어주는데 ref는 참조할 bean을 의미하며 지금 이 xml에서 생성된 bean 중 참조할 bean을 입력하면 됩니다. 다시 설명하면 property는 setter, getter 메서드 중에 하나를 의미합니다. 그리고 여기 적어놓은 name "engine" property setEngine 혹은 getEngine이라는 메서드를 의미하는데 지금 bean 태그 안에 들어가 있고 bean 태그 안에서는 모두 값을 설정하므로 setEngine()이라는 메서드를 의미할 것입니다.
  • Car.java에서 setEngine()이라는 메서드는 파라미터로 Engine 타입을 받는다고 했어요. 그래서 ref 부분은 'id "e"로 선언된 인스턴스를 setEngine() 메서드에 파라미터로 전달해주세요' 이런 의미를 가집니다.
  • 그러니까 지금 여기서 우리가 xml에서 수행해준 것이 실제 메인 메서드에서 실행했다면 2개의 객체를 생성하고 엔진을 자동차에 설정한 것(c.setEngine(e);)까지 실행한 거라고 생각하시면 될 거예요.
applicationConfig.xml 자바 코드로 변환 시

<bean id="e" class="kr.or.connect.diexam01.Engine"></bean>

<bean id="car" class="kr.or.connect.diexam01.Car">

           <property name="engine" ref="e"></property>

</bean>

Engine e = new Engine();

Car c = new Car();

c.setEngine( e );

 

  • 이번에는 이런 설정들을 읽어들여가지고 실행하는 ApplicationContextExam02를 만들겠습니다.
  • 실행하기 위한 ApplicationContextExam02 클래스를 생성하고 메인 메서드를 선언하여 Spring 컨테이너 객체를 생성합니다. Spring 컨테이너 중에 ApplicationContext를 이용할 거고 이 ApplicationContext를 구현하고 있는 ClassPathXmlApplicationContext를 생성합니다. applicationContext.xml에 설정해놓은 정보를 넘기기 위해 ClassPathXmlApplicationContext 클래스의 생성자에다가 해당 xml 파일에 대한 정보를 입력합니다.
  • 그 다음 자동차 객체를 하나 생성합니다. 자동차 객체를 생성하는 것이 이제 주체가 내가 아니라 이 Spring 컨테이너이므로 ApplicationContext가 갖고 있는 getBean()이라는 메서드를 사용하여 자동차 객체를 생성합니다. 이때 applicationContext.xml에다가 등록했던 Bean id를 파라미터로 넘깁니다. 아까 c라고 등록했기 때문에 파라미터에 "c"를 넣고 꺼내오면 엔진을 탑재한 자동차 객체가 만들어졌을 겁니다.
  • 이 자동차가 가진 run()이라는 메서드를 실행하면 콘솔에서 엔진이 먼저 생성되고, 자동차가 생성되고 엔진을 이용해서 달리는데 실제 차의 진짜 엔진 객체가 동작하는 것을 볼 수 있습니다.
  • 콘솔을 보면 다음과 같이 실행된 것을 알 수 있습니다.

ApplicationContextExam02.java

package kr.or.connect.diexam01;

 

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

public class ApplicationContextExam02 {

 

           public static void main(String[] args) {

                      ApplicationContext ac = new ClassPathXmlApplicationContext(

                                             "classpath:applicationContext.xml");

 

                      Car car = (Car)ac.getBean("c");

                      car.run();

           }

}

 

  • 이렇게 어떤 객체에게 객체를 주입하는 것을 DI라고 합니다. DI를 사용했을 때 장점은 사용자가 사용할 클래스만 알고 있으면 된다는 것입니다. Car에 속해 있는 Engine에 대해서는 몰라도 Car를 사용할 수 있다는 것입니다.
  • 나중에 Car를 상속받고 있는 Bus라는 클래스가 생성되도록 xml 파일만 바꿔주고 그리고 Bus가 상속받고 있는 Engine 클래스도 Electric Engine으로 주입받도록 바꿔준다면 실행 클래스의 코드는 하나도 바뀌지 않고 전기 버스가 동작하도록 할 수 있다는 것입니다.
  • 여기까지 xml을 이용해서 bean을 생성하고 주입하는 방법에 대해서 알아보았습니다.
  • Spring이 버전 업이 되면서 xml보다는 어노테이션과 자바 Config를 함께 사용해서 설정하는 방법이 더 많이 이용되고 있습니다. 그러니까 이 방법만 하더라도 일일이 bean을 하나씩 등록해야 되는 점들이 또 불편하다고 생각된 거죠. 그러다 보니 또 버전이 올라가면서 조금 더 편한 방법, 조금 더 편한 방법 이렇게 바뀌어 가는 거 같습니다. 다음 시간에는 이번 시간에 배웠던 설정을 자바 Config와 어노테이션을 이용해서 사용하는 방법으로 수정해보도록 하겠습니다.

생각해보기

  • Spring컨테이너가 관리하는 객체를 빈(Bean)이라고 말합니다. (여러분들이 직접 new연산자로 생성해서 사용하는 객체는 빈(Bean)이라고 말하지 않습니다.) Spring은 빈을 생성할 때 기본적으로 싱글톤(Singleton)객체로 생성합니다. 싱글톤이란 메모리에 하나만 생성한다는 것입니다. 메모리에 하나만 생성되었을 경우, 해당 객체를 동시에 이용한다면 어떤 문제가 발생할 수 있을까요? 이런 문제를 해결하려면 어떻게 해야할까요?   ( 참고로 Spring에서 빈을 생성할 때 스코프(scope)를 줄 수 있습니다. 스코프를 줌으로써 기본으로 설정된 싱글톤 외에도 다른 방법으로 객체를 생성할 수 있습니다. )

참고 자료

[참고링크] Appendix C. XML Schema-based configuration
https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/xsd-config.html

https://www.slipp.net/wiki/pages/viewpage.action?pageId=25528177

 

'부스트코스 웹 프로그래밍 > 3. 웹 앱 개발: 예약서비스 1' 카테고리의 다른 글

8. Spring JDBC - BE (1)  (0) 2019.08.04
7. Spring Core - BE (4)  (0) 2019.08.04
7. Spring Core - BE (2)  (0) 2019.08.03
7. Spring Core - BE (1)  (0) 2019.08.03
6. Tab UI 실습 - FE (2)  (0) 2019.08.03
Comments