Sangwon Coding

2. 스프링의 특징과 의존성 주입 본문

Spring/코드로 배우는 스프링 웹 프로젝트

2. 스프링의 특징과 의존성 주입

SW1 2019. 11. 2. 21:13

안녕하세요! 2번째 포스팅에서 이어서 바로 포스팅 시작하도록 하겠습니다.

1장에서는 예제를 위한 이클립스와 스프링의 기본 설정을 하였고 2장부터는 스프링 프레임워크에 대한 이론적인 부분을 살펴보려고 합니다. 이번 포스팅을 통한 학습 목표는!

 

1. 스프링 프레임워크를 이용해서 '의존성 주입'에 대한 이해와 테스트

2. 스프링에서 XML을 이용하는 객체 관리 방법

3. 스프링의 테스트 환경 구축

 

 

 

스프링의 주요 특징으로는 다음과 같은 점을 들 수 있습니다.

 

1. POJO 기반의 구성

- 스프링의 성격 자체가 가벼운 프레임워크지만 내부에는 객체 간의 관계를 구성할 수 있는 특징을 가지고 있습니다. 스프링은 다른 프레임워크들과 달리 이 관계를 구성할 때 별도의 API 등을 사용하지 않는 POJO(Plain Old Java Object)의 구성만으로 가능하도록 제작되어 있습니다. 쉽게 말해서 여러분이 일반적인 Java 코드를 이용해서 객체를 구성하는 방식을 그대로 스프링에서 사용할 수 있습니다! 이것이 중요한 이유는 코드 개발 시 개발자가 특정 라이브러리나 컨테이너 기술에 종속적이지 않다는 것을 의미하고 생산성에도 유리하게 되며 코드에 대한 테스트 작업도 좀 더 유연하게 할 수 있습니다.

 

2. 의존성 주입(DI)을 통한 객체 간의 관계 구성

- 스프링에 대한 얘기를 하면서 빠지지 않는 개념이 '의존성 주입' 이라는 개념입니다. 스프링에서는 'ApplicationContext'라는 존재가 필요한 객체들을 생성하고, 필요한 객체들을 주입하는 역할을 해주는 구조입니다. 따라서 스프링을 이용하면 개발자들은 기존의 프로그래밍과 달리 객체와 객체를 분리해서 생성하고, 이러한 객체들을 엮는 작업을 하는 형태의 개발을 하게 됩니다. 'ApplicationContext'가 관리하는 객체들을 '빈(Bean)'이라는 용어로 부르고, 빈과 빈 사이의 의존관계를 처리하는 방식으로 XML 설정, 어노테이션 설정, Java 설정 방식을 이용할 수 있습니다.

 

3. AOP(Aspect-Oriented-Programming) 지원

- 스프링은 AOP를 AspectJ의 문법을 통해서 작성할 수 있는데, 이를 통해서 핵심 비즈니스 로직에만 집중해서 코드를 개발할 수 있게 되었고, 각 프로젝트마다 다른 관심사를 적용할 때 코드의 수정을 최소화시킬 수 있었으며, 원하는 관심사의 유지 보수가 수월한 코드를 구성할 수 있습니다.

 

4. 편리한 MVC 구조

 

5. WAS의 종속적이지 않은 개발 환경

 

 

이번엔 직접 예제를 통해 의존성 주입 테스트를 해보겠습니다. 먼저 pom.xml에 추가 혹은 변경해야하는 라이브러리들이 존재합니다.

 

아래는 pom.xml에 추가되는 라이브러리입니다.

 

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.0</version>
            <scope>provided</scope>
        </dependency>

 

아래는 pom.xml에서 변경되는 라이브러리입니다.

 

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>  

 

추가적으로 프로젝트의 Log4j 라이브러리 버전도 1.2.15에서 1.2.17로 바꿔줍니다! (중요)

 

이제 예제 클래스를 생성해 볼텐데 ex00 프로젝트 밑에 'org.zerock.sample' 패키지를 생성하고, Restaurant 클래스와 Chef 클래스를 생성합니다.

 

 

그리고 Chef 클래스와 Restaurant 클래스를 다음과 같이 작성합니다.

 

package org.zerock.sample;

import org.springframework.stereotype.Component;

import lombok.Data;

@Component
@Data
public class Chef {

}
package org.zerock.sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.Data;
import lombok.Setter;

@Component
@Data
public class Restaurant {

	@Setter(onMethod_=@Autowired)
	private Chef chef;
}

 

이때 Lombok의 setter를 생성하는 기능과 생성자, toString() 등을 자동으로 생성하기 위해 @Data 어노테이션을 사용합니다. @Component는 스프링에게 해당 클래스가 스프링에서 관리해야 하는 대상임을 표시하는 어노테이션이고, @Setter는 자동으로 setChef()를 컴파일 시 생성합니다.

 

@Setter에서 사용된 onMethod 속성은 생성되는 setChef()에 @AutoWired 어노테이션을 추가하도록 해서 Lombok으로 생성된 클래스에 대한 정보는 이클립스를 통해 확인할 수 있습니다.

 

 

XML을 이용하는 의존성 주입을 설정해보겠습니다. 스프링에서 관리되는 객체를 흔히 '빈(Bean)'이라고 하고, 이에 대한 설정은 XML과 Java를 이용해서 처리할 수 있습니다. 프로젝트의 src 폴더 내에 'root-context.xml'을 클릭 후 아래쪽에 'NameSpaces' 탭을 들어가서 'Context' 항목을 체크합니다.

 

 

 

'Source' 탭을 선택해서 코드 일부를 추가합니다.

 

<?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 https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<!-- Root Context: defines shared resources visible to all other web components -->

	<context:component-scan
		base-package="org.zerock.sample"></context:component-scan>
</beans>

 

변경된 XML 을 저장하고 'Bean Graph' 탭을 선택해 보면 Restaurant와 Chef 객체가 설정된 것을 확인할 수 있습니다.

 

 

이제 테스트 코드를 통해 확인을 해보겠습니다. 프로젝트 내 'src/test/java' 폴더 내에 'org.zerock.sample.SampleTests' 클래스를 추가합니다. 소스 코드는 아래와 같습니다.

 

 

package org.zerock.sample;
 
import static org.junit.Assert.assertNotNull;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
import lombok.Setter;
import lombok.extern.log4j.Log4j;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class SampleTests {
 
    @Setter(onMethod_ = {@Autowired})
    private Restaurant restaurant;
    
 
    @Test
    public void testExist() {
        assertNotNull(restaurant);
        
        log.info(restaurant);
        log.info("-----------------------------");
        log.info(restaurant.getChef());
        
    }
}

 

해당 클래스의 'Run As -> Junit Test' 를 실행시켜보면 결과는 다음과 같이 나옵니다! 객체가 정상적으로 생성된 것을 확인할 수가 있습니다.

 

 

실행결과에서 주목해야할 부분으로는 

 

1. new Rastaurant()와 같이 Rastaurant클래스에서 객체를 생성한 적이 없는데 객체가 만들어진 점 (스프링은 관리가 필요한 객체(bean)를 어노테이션 등을 이용해서 객체를 생성하고 관리하는 일종의 컨테이너나 팩토리 기능을 가지고 있다.)

 

2. Rastaurant클래스의 @Data로 Lombok을 이용해서  여러 매서드가 만들어진 점 (Lombok은 자동으로 getter/setter 등을 만들어주는데 스프링은 생성자 주입혹은 setter 주입을 이용해서  동작함. 'onMethod' 속성을 이용해서 작성된 setter에 @Autowired 추가)

 

3. Rastaurant 객체의 Chef 인스턴스 변수에 Chef 타입의 객체가 주입되어 있다는 점 (스프링은 @Autowired와 같은 것을 이용해서  개발자가 직접 객체들과의 관계를 관리하지 않고, 자동으로 관리하도록 한다.) 

 

테스트 결과가 의미하는 바

 

1) 테스트 코드가 실행되기 위해서 스프링 프레임워크가 동작했고

 

2) 동작하는 과정에서 필요한 객체들이 스프링에등록되었고

 

3) 의존성 주입이 필요한 객체는 자동으로 주입이 이루어졌다.

 

 

이상으로 스프링의 특징과 의존성 주입 포스팅을 마치고 다음 포스팅부터는 스프링과 Oracle Database를 연동시켜 보는 것을 해보겠습니다.

Comments