챕터 13: Spring 프레임워크
Spring 프레임워크는 Java 플랫폼을 위한 강력한 애플리케이션 프레임워크로, 주로 엔터프라이즈 애플리케이션 개발에 사용됩니다. 이 장에서는 Spring 프레임워크의 개요와 설정, 의존성 주입(DI), AOP(Aspect-Oriented Programming), 그리고 Spring Boot를 활용한 웹 애플리케이션 개발에 대해 다룹니다.
13.1 Spring의 개요와 설정
Spring 프레임워크는 경량 컨테이너로, 애플리케이션의 객체를 구성하고 관리합니다. Spring의 주요 철학은 IoC(Inversion of Control)와 DI(Dependency Injection)입니다.
배경과 역사
Spring 프레임워크는 2003년 로드 존슨(Rod Johnson)이 처음 발표한 'Expert One-on-One J2EE Design and Development'라는 책에서 시작되었습니다. 당시 Java EE(EJB - Enterprise JavaBeans) 기반의 애플리케이션 개발은 복잡하고 무겁다는 비판을 받았습니다. 개발자들은 간단한 업무를 수행하기 위해서도 복잡한 설정과 코드 작성을 해야 했고, 이는 생산성 저하로 이어졌습니다.
Spring은 이러한 문제를 해결하고자 경량화된 프레임워크로 개발되었습니다. Spring은 POJO(Plain Old Java Object)를 기반으로 하여 복잡한 EJB 대신 단순한 Java 객체를 사용하여 개발을 용이하게 했습니다. 또한, IoC와 DI를 통해 객체 간의 의존성을 관리하고, AOP를 통해 횡단 관심사를 분리하는 방식을 제안함으로써 모듈화와 유지보수성을 높였습니다.
13.1.1 Spring 프레임워크의 철학과 주요 기능
- IoC(Inversion of Control): 객체의 생성과 의존성 관리를 프레임워크에 맡기는 설계 원칙입니다. IoC 컨테이너가 객체의 생명 주기를 관리하며, 의존성을 주입합니다. IoC는 제어의 주체가 사용자가 아닌 프레임워크로 전환됨을 의미합니다.
- DI(Dependency Injection): 객체 간의 의존성을 외부에서 주입하여 결합도를 낮추고 테스트 용이성을 높입니다. DI는 IoC의 구현 방법 중 하나입니다.
- AOP(Aspect-Oriented Programming): 핵심 비즈니스 로직과 횡단 관심사를 분리하여 모듈화를 향상시킵니다. AOP는 로깅, 트랜잭션 관리, 보안 등의 공통 기능을 비즈니스 로직과 분리하여 유지보수성을 높입니다.
- 트랜잭션 관리(Transaction Management): 선언적 트랜잭션 관리로 코드의 분리를 유지하면서 트랜잭션을 관리합니다. Spring은 트랜잭션 관리에 대한 일관된 프로그래밍 모델을 제공합니다.
- Spring MVC: 웹 애플리케이션 개발을 위한 프레임워크로, MVC(Model-View-Controller) 패턴을 구현합니다. Spring MVC는 요청을 처리하고 적절한 뷰를 반환하는 웹 애플리케이션을 쉽게 개발할 수 있게 합니다.
- 빈(Bean) 관리: Spring IoC 컨테이너는 애플리케이션에 필요한 빈(Bean)을 생성하고 관리합니다. 빈은 Spring 컨테이너에서 생성되고 관리되는 객체를 의미합니다.
- 데이터 접근(Data Access): Spring은 JDBC, JPA, MyBatis 등 다양한 데이터 접근 기술을 지원하여 데이터베이스와의 상호 작용을 쉽게 합니다.
- 테스트 지원: Spring은 통합 테스트, 단위 테스트 등 다양한 테스트 기능을 지원하여 애플리케이션의 안정성을 높입니다.
13.1.2 프로젝트 설정과 의존성 관리
Spring 프로젝트를 설정하기 위해서는 Maven 또는 Gradle과 같은 빌드 도구를 사용하여 의존성을 관리합니다. 여기서는 Maven을 예로 들어 설명합니다.
Maven 프로젝트 설정
- pom.xml 파일에 Spring 의존성 추가:
<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>com.example</groupId>
<artifactId>spring-example</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>11</java.version>
<spring.version>5.3.9</spring.version>
</properties>
<dependencies>
<!-- Spring Core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 프로젝트 디렉토리 구조 설정
spring-example/
└── src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── SpringExampleApplication.java
│ └── resources/
│ └── application.properties
└── test/
├── java/
└── resources/
SpringExampleApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringExampleApplication.class, args);
}
}
설명:
- @SpringBootApplication: Spring Boot 애플리케이션의 시작점을 정의하는 애너테이션입니다. 이 애너테이션은 @Configuration, @EnableAutoConfiguration, @ComponentScan을 포함하여 Spring Boot의 기본 설정을 제공합니다.
- SpringApplication.run: Spring Boot 애플리케이션을 실행하는 메서드입니다. 애플리케이션 컨텍스트를 초기화하고, 필요한 빈을 생성하며, 내장 서버를 시작합니다.
13.2 DI(Dependency Injection)
DI는 객체 간의 의존성을 주입하여 결합도를 낮추고, 테스트 용이성을 높이는 설계 패턴입니다. Spring에서는 다양한 방식으로 DI를 구현할 수 있습니다.
배경과 역사
DI와 IoC는 소프트웨어 개발에서 객체 간의 결합도를 줄이기 위해 도입된 개념입니다. 초기 소프트웨어 개발에서는 객체가 다른 객체를 직접 생성하고 관리하는 방식으로 개발되었습니다. 이러한 방식은 결합도가 높아져, 객체 간의 의존성이 강하게 형성되었고, 이는 유지보수와 테스트를 어렵게 만들었습니다.
IoC와 DI는 객체 간의 의존성을 외부에서 주입하는 방식을 통해 결합도를 낮추고, 객체 간의 독립성을 높였습니다. 이는 객체를 쉽게 교체하거나 테스트할 수 있게 하여, 개발 생산성을 높이고 유지보수성을 향상시켰습니다.
13.2.1 DI의 개념과 Spring에서의 구현 방법
- 필드 주입(Field Injection): 객체의 필드에 직접 주입합니다. 사용하기 간편하지만, 필드가 private이므로 테스트가 어려울 수 있습니다.
- 생성자 주입(Constructor Injection): 객체의 생성자를 통해 주입합니다. 객체 생성 시점에 모든 의존성을 주입받아야 하므로, 의존성이 불변으로 유지됩니다.
- 세터 주입(Setter Injection): 세터 메서드를 통해 주입합니다. 선택적 의존성을 주입할 때 유용합니다.
예제: 필드 주입
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class FieldInjectionExample {
@Autowired
private MyService myService;
public void execute() {
myService.performService();
}
}
예제: 생성자 주입
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ConstructorInjectionExample {
private final MyService myService;
@Autowired
public ConstructorInjectionExample(MyService myService) {
this.myService = myService;
}
public void execute() {
myService.performService();
}
}
예제: 세터 주입
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SetterInjectionExample {
private MyService myService;
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
public void execute() {
myService.performService();
}
}
MyService.java
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void performService() {
System.out.println("Service is performed.");
}
}
설명:
- @Autowired: Spring 프레임워크가 의존성을 자동으로 주입하도록 하는 애너테이션입니다. 필드, 생성자, 세터 메서드에 사용할 수 있습니다.
- @Component: Spring이 관리하는 빈(Bean)으로 등록하는 클래스에 사용합니다. @Service, @Repository, @Controller와 같은 특화된 애너테이션도 있습니다.
- @Service: 서비스 레이어에서 사용되는 클래스에 사용합니다. @Component와 기능적으로 동일하지만, 역할을 더 명확하게 표현합니다.
13.3 AOP(Aspect-Oriented Programming)
AOP는 횡단 관심사(Cross-Cutting Concerns)를 모듈화하여 핵심 비즈니스 로직과 분리하는 프로그래밍 패러다임입니다. Spring에서는 AOP를 사용하여 로깅, 트랜잭션 관리 등의 기능을 구현할 수 있습니다.
배경과 역사
AOP는 1990년대 후반 제록스 팰로앨토 연구소에서 개발된 기술입니다. AOP는 객체 지향 프로그래밍(OOP)의 단점을 보완하기 위해 도입되었습니다. OOP는 핵심 비즈니스 로직과 횡단 관심사를 분리하는 데 한계가 있었습니다. 예를 들어, 로깅, 보안, 트랜잭션 관리와 같은 횡단 관심사는 여러 모듈에 걸쳐 반복적으로 나타나기 때문에 코드 중복과 유지보수의 어려움이 발생했습니다.
AOP는 이러한 문제를 해결하기 위해 횡단 관심사를 모듈화하여 핵심 비즈니스 로직과 분리할 수 있는 방법을 제공합니다. 이를 통해 코드 중복을 줄이고, 유지보수성을 높일 수 있습니다.
13.3.1 AOP의 개념과 필요성
- 횡단 관심사(Cross-Cutting Concerns): 여러 모듈에서 공통으로 사용되는 기능입니다. 예: 로깅, 보안, 트랜잭션 관리
- Aspect: 횡단 관심사를 모듈화한 것입니다. AOP에서의 핵심 단위입니다.
- Advice: 특정 시점에 실행되는 코드입니다. 예: 메서드 실행 전, 후, 예외 발생 시
- Join Point: Advice가 적용될 수 있는 지점입니다. 예: 메서드 호출
- Pointcut: Advice가 적용될 지점을 정의하는 표현식입니다.
- Weaving: Aspect와 다른 애플리케이션 타입을 결합하는 과정입니다.
13.3.2 Spring에서의 AOP 구현
Spring AOP는 주로 애너테이션과 XML 설정을 통해 구현됩니다.
예제: AOP 구현
LoggingAspect.java
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.MyService.*(..))")
public void logBefore() {
System.out.println("Method execution started.");
}
}
설명:
- @Aspect: 이 클래스가 AOP에서 사용될 것을 나타냅니다.
- @Before: 메서드 실행 전에 실행될 Advice를 정의합니다.
- execution(* com.example.MyService.*(..)): MyService 클래스의 모든 메서드에 적용되는 Pointcut 표현식입니다.
SpringExampleApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringExampleApplication.class, args);
}
}
MyService.java
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void performService() {
System.out.println("Service is performed.");
}
}
추가 예제: AOP를 통한 예외 처리
ExceptionHandlingAspect.java
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ExceptionHandlingAspect {
@AfterThrowing(pointcut = "execution(* com.example.MyService.*(..))", throwing = "ex")
public void handleException(Exception ex) {
System.out.println("Exception caught: " + ex.getMessage());
}
}
설명:
- @AfterThrowing: 메서드 실행 중 예외가 발생한 후에 실행될 Advice를 정의합니다.
- throwing = "ex": 발생한 예외를 파라미터로 받습니다.
- 위 코드에서는 MyService 클래스의 메서드에서 예외가 발생하면 예외 메시지를 출력합니다.
13.4 Spring Boot를 활용한 웹 애플리케이션
Spring Boot는 Spring 프레임워크를 기반으로 한 프로젝트로, 복잡한 설정 없이 빠르게 애플리케이션을 개발할 수 있게 도와줍니다. Spring Boot는 내장 서버, 자동 설정, 프로덕션 준비 기능 등을 제공합니다.
배경과 역사
Spring Boot는 2014년 처음 출시되었습니다. Spring 프레임워크는 강력한 기능을 제공하지만, 초기 설정과 구성이 복잡하다는 단점이 있었습니다. Spring Boot는 이러한 문제를 해결하고자, Spring 기반 애플리케이션의 설정과 구성을 간소화하고, 빠르게 애플리케이션을 개발할 수 있도록 설계되었습니다.
Spring Boot는 내장 서버를 제공하여 별도의 서버 설정 없이 애플리케이션을 실행할 수 있으며, 다양한 스타터 패키지를 통해 필요한 의존성을 쉽게 추가할 수 있습니다. 또한, 프로덕션 환경에서의 운영을 용이하게 하는 다양한 기능을 제공합니다.
13.4.1 Spring Boot의 특징과 장점
- 자동 설정(Auto Configuration): 대부분의 설정을 자동으로 수행하여 개발자의 부담을 줄입니다.
- 내장 서버(Embedded Server): Tomcat, Jetty, Undertow와 같은 내장 서버를 포함하여 별도의 서버 설치 없이 실행할 수 있습니다.
- 프로덕션 준비 기능(Production-Ready Features): 헬스 체크, 메트릭스, 외부 설정 등을 통해 프로덕션 환경에서의 운영을 용이하게 합니다.
- Spring Boot Starter: 프로젝트에 필요한 의존성을 쉽게 추가할 수 있는 스타터 패키지를 제공합니다.
13.4.2 RESTful 웹 서비스 개발
Spring Boot를 사용하여 RESTful 웹 서비스를 쉽게 개발할 수 있습니다.
예제: RESTful 웹 서비스 개발
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>com.example</groupId>
<artifactId>spring-boot-example</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SpringBootExampleApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootExampleApplication.class, args);
}
}
GreetingController.java
package com.example;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(String.format("Hello, %s!", name));
}
}
Greeting.java
package com.example;
public class Greeting {
private final String message;
public Greeting(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
설명:
- @SpringBootApplication: Spring Boot 애플리케이션의 시작점을 정의하는 애너테이션입니다.
- @RestController: RESTful 웹 서비스를 처리하는 컨트롤러 클래스에 사용됩니다.
- @GetMapping: HTTP GET 요청을 처리하는 메서드에 사용됩니다.
- 위 코드에서는 GreetingController를 통해 /greeting 엔드포인트를 처리하고, 이름을 받아 맞춤형 인사를 반환하는 RESTful 웹 서비스를 구현합니다.
추가 예제: POST 요청 처리
GreetingController.java
package com.example;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(String.format("Hello, %s!", name));
}
@PostMapping("/greeting")
public Greeting createGreeting(@RequestBody Greeting greeting) {
return new Greeting(String.format("Created greeting: %s", greeting.getMessage()));
}
}
설명:
- @PostMapping: HTTP POST 요청을 처리하는 메서드에 사용됩니다.
- @RequestBody: HTTP 요청 본문을 매핑하여 파라미터로 사용합니다.
- 위 코드에서는 POST /greeting 엔드포인트를 처리하고, 요청 본문으로 전달된 Greeting 객체를 생성하여 응답합니다.
이로써 Spring 프레임워크의 개요와 설정, 의존성 주입(DI), AOP, 그리고 Spring Boot를 활용한 웹 애플리케이션 개발에 대해 자세히 설명했습니다. 이를 통해 Spring을 활용한 엔터프라이즈 애플리케이션 개발 방법을 이해하고 활용할 수 있게 됩니다. 다음 챕터에서는 데이터베이스 연동과 관련된 내용을 다루겠습니다.
'IT 강좌(IT Lectures) > Java' 카테고리의 다른 글
15강. 테스팅과 유지보수 (0) | 2024.07.02 |
---|---|
14강. 데이터베이스 연동 (0) | 2024.07.01 |
12강. 보안과 암호화 (0) | 2024.06.29 |
11강. Java 성능 최적화 (0) | 2024.06.28 |
10강. 기초 프로젝트 (0) | 2024.06.27 |