2. 스프링 시작하기

스프링 5 프로그래밍 입문 2/7

1. 스프링 프로젝트 시작하기

스프링을 이용한 자바 프로젝트를 진행하는 과정은 다음과 같다.

  • 메이븐 프로젝트 생성(또는 그레이들 프로젝트 생성)

  • 이클립스에서 메이븐 프로젝트 임포트

  • 스프링에 맞는 자바 코드와 설정 파일 작성

  • 실행

1.1 프로젝트 폴더 생성

메이븐과 그레이들 모두 동일한 폴더 구조를 사용한다. 생성할 폴더구조는 다음과 같다.

C:\spring\example\ : 프로젝트 폴더

+ C:\spring\example\src\main\java : 자바 소스 폴더

1.2 메이븐 프로젝트 생성

다음 할 작업은 메이븐 프로젝트 설정 파일을 작성하는 것이다. 프로젝트 폴더 위치에 pom.xml 파일을 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<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>sp5</groupId>
	<artifactId>sp5-chap02</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.0.2.RELEASE</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.7.0</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>utf-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

<artifactId>sp5-chap02</artifactId>: 프로젝트의 식별자를 지정한다. 여기서는 프로젝트와 동일한 이름을 사용한다.

<dependency> ~ </dependency> : 프로젝트에서 5.0.2.RELEASE 버전의 spring-context 모듈을 사용한다고 설정한다.

<plugin> ~ </plugin> : 1.8 버전을 기준으로 자바 소스를 컴파일하고 결과 클래스를 생성한다. 자바 컴파일러가 소스 코드를 읽을 때 사용할 인코딩은 UTF-8로 설정한다.

메이븐 프로젝트에서 핵심은 pom.xml 파일이다. 모든 메이븐 프로젝트는 프로젝트의 루트 폴더에 pom.xml 파일을 갖는다. pom.xml은 메이븐 프로젝트에 대한 설정 정보를 관리하는 파일로서 프로젝트에서 필요로 하는 의존 모듈이나 플러그인 등에 대한 설정을 담는다.

1.2.1 메이븐 의존 설정

메이븐 의존 설정은 다음과 같다.

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.0.2.RELEASE</version>
</dependency>

메이븐은 한 개의 모듈을 아티팩트라는 단위로 관리한다. 위 설정은 spring-context라는 식별자를 가진 5.0.2 버전의 아티팩트에 대한 의존(dependency)을 추가한 것이다. 여기서 의존을 추가한다는 것은 일반적인 자바 어플리케이션에서 클래스 패스에 spring-context 모듈을 추가한다는 것을 뜻한다. 위 설정은 메이븐 프로젝트의 소스 코드를 컴파일하고 실행할 때 사용할 클래스 패스에 spring-context-5.0.2.RELEASE.jar(아티팩트이름-버전.jar) 파일을 추가한다는 것을 의미한다.

1.2.2 메이븐 리포지토리

메이븐은 코드를 컴파일하거나 실행할 때 <dependency>로 설정한 아티팩트 파일을 사용한다. 아티팩트 파일은 다음 과정을 거쳐서 구한다.

  • 메이븐 로컬 리포지토리에서 [그룹ID]\[아티팩트ID]\[버전] 폴더에 아티팩트ID-버전.jar 형식의 이름을 갖는 파일이 있는지 검사한다. 파일이 존재하면 이 파일을 사용한다.

  • 로컬 리포지토리에 파일이 없으면 메이븐 원격 중앙 리포지토리로부터 해당 파일을 다운로드하여 로컬 리포지토리에 복사한 뒤 그 파일을 사용한다.

메이븐은 기본적으로 [사용자홈폴더\.m2\repository 폴더를 로컬 리포지토리로 사용한다. 앞서 의존 설정에서 아티팩트 파일이 위치하는 경로는 다음과 같다.

[사용자홈폴더]\.m2\repository\org\springframework\spring-context\5.0.2.RELEASE

메이븐 프로젝트는 실제로 이 파일이 필요할 때 원격 리포지토리에서 다운로드한다. 명령 프롬로트에서 앞서 생성한 프로젝트 폴더로 이동한 뒤 mvn compile 명령을 실행해보자. 위 경로에 spring-context-5.0.2.RELEASE.jar 파일이 생성된 것을 확인할 수 있다.

로컬 리포지토리에 아티팩트 파일을 다운로드하면, 이후에는 원격 리포지토리에서 다운로드 하지 않는다.

1.2.3 의존 전이(Transitive Dependencies)

앞서 처음 mvn compile을 실행하면 spring-context-5.0.2.RELEASE.jar 파일 외에 다양한 아티팩트 파일을 다운로드하는 것을 확인할 수 있다. 이 파일에는 컴파일을 수행하는데 필요한 메이븐 컴파일러 플러그인과 같이 메이븐과 관련된 파일이 포함된다. 추가로 의존(<dependency>)에서 설정한 아티팩트가 다시 의존하는 파일도 포함된다.

spring-context를 사용하려면 spring-aop, spring-beans 등의 다른 아티팩트도 추가로 필요하다. 따라서 메이븐은 spring-context에 대하 의존 설정이 있으면 spring-context가 의존하는 다른 아티팩트도 함께 다운로드한다. 의존한 아티팩트가 또다시 의존하고 있는 다른 아티팩트가 있다면 그 아티팩트도 함께 다운로드한다. 이렇게 의존 대상이 다시 의존 대상까지도 의존 대상에 포함하기 때문에 이를 의존 전이(Transitive Dependencies)라고 한다.

1.2.4 메이븐 기본 폴더 구조

sp5-chapXX
├── pom.xml
├──── src
			 └── main
						├── java
						├── resources
						└── webapp
									└── WEB-INF
									└── web.xml

이 폴더 구조는 메이븐에 정의되어 있는 기본 폴더 구조로서 src\main\java 폴더에는 자바 소스 코드가 위치한다.

XML이나 프로퍼티 파일과 같이 자바 소스 이외의 다른 자원 파일이 필요하다면 src\main\resources 폴더에 해당 파일을 위치시키면 된다.

웹 어플리케이션을 개발할 때는 src\main\webapp 폴더를 웹 어플리케이션 기준 폴더로 사용한다.

1.2.5 메이븐 프로젝트 임포트

메이븐 프로젝트를 이클립스에 임포트하려면 [File] → [Import..] 메뉴를 사용한다. 여기서 [Browse] 버튼을 눌러 앞서 생성한 메이븐 프로젝트 폴더를 Root Directory로 선택한다.

이클립스에 생성된 프로젝트를 보면 다음을 알 수 있다.

  • src\main\java 폴더

    소스 폴더로 정의되어 있음

  • Maven Dependencies

    메이븐 의존에 설정한 아티팩트가 이클립스 프로젝트의 클래스패스에 추가됨

1.4 예제 코드 작성

huewilliams/spring-example-and-summaryYou can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or window. Reload to refresh your session. Reload to refresh your session.https://github.com/huewilliams/spring-example-and-summary/tree/master/%5Bbook%5Dspring5ITP/002.%20start%20spring/src/main/java/chap02

2. 스프링은 객체 컨테이너

스프링의 핵심 기능은 객체를 생성하고 초기화하는 것이다. 이와 관련된 기능은 ApplicationContext라는 인터페이스에 정의되어 있다.

위 그림은 AnnotationConfigApplicationContext 클래스의 계층도 일부이다. 계층도 최상위의 BeanFactory 인터페이스는 개체 생성과 검색에 대한 기능을 정의한다. 객체를 검색하는 것 이외에 싱글톤/프로토타입 빈인지 확인하는 기능도 제공한다.

ApplicationContext 인터페이스는 메시지, 프로필/환경 변수 등을 처리할 수 있는 기능을 추가로 정의한다.

앞서 예제에서 사용한 AnnotationConfigApplicationContext를 비롯해 계층도의 가장 하단에 위치한 세 개의 클래스는 BeanFactory와 ApplicationContext에 정의된 기능의 구현을 제공한다. 각 클래스의 차이점은 다음과 같다.

  • AnnotationConfigApplicationContext : 자바 애노테이션을 이용해서 클래스로부터 객체 설정 정보를 가져온다.

  • GenericXmlApplicaitonContext : XML로 부터 객체 설정 정보를 가져온다.

  • GenericGroovyApplicationContext : 그루비 코드를 이용해 설정 정보를 가져온다.

어떤 구현 클래스를 사용하든, 각 구현 클래스는 설정 정보로부터 빈(Bean)이라고 불리는 객체를 생성하고 그 객체를 내부에 보관한다. 그리고 getBean() 메서드를 실행하면 해당하는 빈 객체를 제공한다.

ApplicationContext(또는 BeanFactory)는 빈 객체의 생성, 초기화, 보관, 제거 등을 관리하고 있어서 ApplciationContext를 컨테이너(Container)라고도 부른다. 스프링 컨테이너는 내부적으로 빈 객체와 빈 이름을 연결하는 정보를 갖는다. 이름과 실제 객체의 관계 뿐만 아니라 실제 객체의 생성, 초기화, 의존 주입 등 스프링 컨테이너는 객체 관리를 위한 다양한 기능을 제공한다.

2.1 싱글톤(Singleton) 객체

아래 예제를 통해 싱글톤 객체에 대해 알아보자.

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = 
			new AnnotationConfigApplicationContext(AppContext.class);
		Greeter g1 = ctx.getBean("greeter", Greeter.class);
		Greeter g2 = ctx.getBean("greeter", Greeter.class);
		System.out.println("g1 == g2 :" + g1 == g2) //true
		ctx.close();
	}
}

(g1 == g2)의 결과가 true라는 것은 g1과 g2가 같은 객체라는 것을 의미한다. 즉 getBean()메서드는 같은 객체를 리턴하는 것이다. 별도 설정을 하지 않을 경우 스프링은 한 개의 빈 객체만을 생성하며, 이때 빈 객체는 싱글톤(singleton) 범위를 갖는다고 표현한다. 싱글톤은 단일 객체(single object)를 의미하는 단어로서 스프링은 기본적으로 한 개의 @Bean 애노테이션에 대해 한 개의 빈 객체를 생성한다.

따라서 다음과 같은 설정을 사용하면 "greeter"에 해당하는 객체 한 개와 "greeter1"에 해당하는 객체 한 개, 이렇게 두 개의 빈 객체가 생성된다.

@Bean
public Greeter greeter() {
	Greeter g = new Greeter();
	g.setFormat("%s 안녕하세요!");
	return g;
}

@Bean
public Greeter greeter1() {
	Greeter g = new Greeter();
	g.setFormat("안녕하세요, %s님!");
	return g;
}

Last updated

Was this helpful?