Now Loading ...
-
🏛️[SpringBoot] 스프링 부트의 핵심 개념 - 관점 지향 프로그래밍
🏛️[SpringBoot] 스프링 부트의 핵심 개념 - 관점 지향 프로그래밍
AOP란?
자바에서는 재사용 가능한 코드를 만들기 위해 객체 지향 프로그래밍(OOP)을 사용합니다. 클래스를 작성하고 객체를 생성하며, 공통 기능은 부모 클래스로 작성해 상속을 통해 재사용합니다.
하지만 자바는 수직적 상속 외에도 수평적으로 공통 관심사를 구현하는 방법을 제공하는데, 이것이 바로 관점 지향 프로그래밍(AOP, Aspect Oriented Programming)입니다.
Spring Boot는 AOP를 쉽고 편리하게 구현할 수 있도록 Spring AOP를 제공합니다.
실전 예제: 메서드 실행 시간 측정
문제 상황
몬테카를로 기법으로 원주율을 계산하는 메서드가 있다고 가정해봅시다. 이 메서드의 실행 시간을 측정하려면 다음과 같이 코드를 작성해야 합니다.
// PiCalculator.java
public class PiCalculator {
public static void main(String[] args) {
PiCalculator pi = new PiCalculator();
System.out.println(pi.calculate(100000000));
}
double calculate(int points) {
long start = System.currentTimeMillis();
int circle = 0;
for (long i = 0; i < points; i++) {
double x = Math.random() * 2 - 1;
double y = Math.random() * 2 - 1;
if (x * x + y * y <= 1) {
circle++;
}
}
long executionTime = System.currentTimeMillis() - start;
System.out.println("executed in " + executionTime + "ms.");
return 4.0 * circle / points;
}
}
문제점: 실행 시간을 측정하고 싶은 메서드가 여러 개라면 매번 이런 코드를 반복해야 합니다.
AOP를 활용한 해결책
다음과 같이 애노테이션 하나만 추가하면 자동으로 실행 시간이 측정된다면 얼마나 편할까요?
@PrintExecutionTime
double calculate(int points) {
int circle = 0;
for (long i = 0; i < points; i++) {
double x = Math.random() * 2 - 1;
double y = Math.random() * 2 - 1;
if (x * x + y * y <= 1) {
circle++;
}
}
return 4.0 * circle / points;
}
이것이 바로 AOP의 장점입니다!
Spring AOP 설정
1. 의존성 추가
build.gradle 파일에 다음 의존성을 추가합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-aop'
}
⚠️ Spring AOP는 Spring Initializr에서 직접 추가할 수 없으므로 수동으로 추가해야 합니다.
AOP 구현하기
2. 커스텀 애노테이션 정의
// PrintExecutionTime.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PrintExecutionTime {
}
주요 설정:
@Target(ElementType.METHOD): 메서드에만 적용 가능
@Retention(RetentionPolicy.RUNTIME): 런타임에 동작 (컴파일 시점이 아님)
3. Aspect 클래스 구현
// PrintExecutionTimeAspect.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class PrintExecutionTimeAspect {
@Around("@annotation(PrintExecutionTime)")
public Object printExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
System.out.println("executed " + joinPoint.toShortString() +
" with " + joinPoint.getArgs().length +
" args in " + executionTime + "ms.");
return result;
}
}
동작 원리:
@PrintExecutionTime이 붙은 메서드가 호출되면
실제 메서드 대신 printExecutionTime 메서드가 먼저 실행됨
joinPoint.proceed()로 원래 메서드를 호출
전후로 추가 로직(실행 시간 측정) 수행
4. 애노테이션 적용
// Pi.java
import org.springframework.stereotype.Component;
@Component
public class Pi {
@PrintExecutionTime
double calculate(int points) {
int circle = 0;
for (long i = 0; i < points; i++) {
double x = Math.random() * 2 - 1;
double y = Math.random() * 2 - 1;
if (x * x + y * y <= 1) {
circle++;
}
}
return 4.0 * circle / points;
}
}
5. 실행 예제
// PiApplication.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class PiApplication implements ApplicationRunner {
@Autowired
private Pi pi;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("PI with 10,000 points = " + pi.calculate(10000));
System.out.println("PI with 100,000 points = " + pi.calculate(100000));
System.out.println("PI with 1,000,000 points = " + pi.calculate(1000000));
System.out.println("PI with 10,000,000 points = " + pi.calculate(10000000));
System.out.println("PI with 100,000,000 points = " + pi.calculate(100000000));
}
}
실행 결과
executed execution(Pi.calculate(..)) with 1 args in 1ms.
PI with 10,000 points = 3.1376
executed execution(Pi.calculate(..)) with 1 args in 4ms.
PI with 100,000 points = 3.14336
executed execution(Pi.calculate(..)) with 1 args in 18ms.
PI with 1,000,000 points = 3.141108
executed execution(Pi.calculate(..)) with 1 args in 169ms.
PI with 10,000,000 points = 3.1411124
executed execution(Pi.calculate(..)) with 1 args in 1724ms.
PI with 100,000,000 points = 3.14153364
Spring AOP 주요 애노테이션
1. @Before
메서드 실행 전에 수행할 로직을 구현합니다.
@Component
@Aspect
public class PrintExecutionTimeAspect {
@Before("@annotation(PrintExecutionTime)")
public void beforePrintExecutionTime(JoinPoint joinPoint) {
System.out.println("do something before " + joinPoint.toShortString() +
" with " + joinPoint.getArgs().length + " args.");
}
}
2. @After
메서드 실행 후에 수행할 로직을 구현합니다 (예외 발생 여부와 무관하게 항상 실행).
@Component
@Aspect
public class PrintExecutionTimeAspect {
@After("@annotation(PrintExecutionTime)")
public void afterPrintExecutionTime(JoinPoint joinPoint) {
System.out.println("do something after " + joinPoint.toShortString() +
" with " + joinPoint.getArgs().length + " args.");
}
}
3. @AfterReturning
메서드가 정상적으로 반환값을 리턴한 후에 수행할 로직을 구현합니다.
@Component
@Aspect
public class PrintExecutionTimeAspect {
@AfterReturning(
pointcut = "@annotation(PrintExecutionTime)",
returning = "result"
)
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("afterReturning " + joinPoint.toShortString()
+ " with " + joinPoint.getArgs().length
+ " args returning " + result.toString());
}
}
4. @AfterThrowing
메서드 실행 중 예외가 발생했을 때 수행할 로직을 구현합니다.
@Component
@Aspect
public class PrintExecutionTimeAspect {
@AfterThrowing(
pointcut = "@annotation(PrintExecutionTime)",
throwing = "ex"
)
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
System.out.println("afterThrowing " + joinPoint.toShortString()
+ " with " + joinPoint.getArgs().length
+ " args throwing " + ex.toString());
}
}
5. @Around
메서드 실행 전후 모두를 제어할 수 있는 가장 강력한 애노테이션입니다.
AOP 애노테이션 비교표
애노테이션
실행 시점
예외 처리
반환값 접근
메서드 실행 제어
주요 용도
@Before
메서드 실행 전
무관
✗
✗
인증, 로깅, 파라미터 검증
@After
메서드 실행 후(항상)
포함
✗
✗
리소스 정리, 공통 후처리
@AfterReturning
메서드 정상 종료 후
예외 시 미실행
✓
✗
반환값 로깅, 응답 후처리
@AfterThrowing
메서드 예외 발생 후
전용
✗
✗
예외 로깅, 예외 전환
@Around
메서드 실행 전/후 모두
포함
✓
✓
트랜잭션, 성능 측정, 전체 제어
실무에서의 AOP 활용
Spring Boot는 AOP를 기반으로 다양한 애노테이션을 제공합니다. 가장 대표적인 예가 @Transactional입니다.
@Transactional
public void saveUser(User user) {
userRepository.save(user);
// 메서드 실행 전: BEGIN TRANSACTION
// 메서드 실행 후: COMMIT (또는 예외 시 ROLLBACK)
}
@Transactional 애노테이션만 추가하면 자동으로 트랜잭션 처리가 되어 매우 편리합니다.
정리
AOP의 핵심 장점:
✅ 중복 코드 제거
✅ 비즈니스 로직과 부가 기능 분리
✅ 코드 유지보수성 향상
✅ 수평적 관심사 처리
Spring AOP를 활용하면 로깅, 트랜잭션, 보안, 성능 측정 등의 공통 관심사를 효율적으로 관리할 수 있습니다.
-
-
🏛️[SpringBoot] 스프링 부트란 무엇일까요?
🏛️[SpringBoot] 스프링 부트란 무엇일까요?
📖 개요
SpringBoot는 Spring Framework를 기반으로 한 Java 백엔드 애플리케이션 개발 프레임워크입니다. 복잡한 설정 과정을 자동화하고, 내장 서버를 제공하여 개발자가 비즈니스 로직에 더 집중할 수 있도록 도와줍니다.
🤔 왜 프레임워크가 필요한가?
규모가 크고 복잡한 애플리케이션을 개발할 때, 개발자가 처음부터 끝까지 모든 부분을 개발하는 것은 비효율적입니다. 프레임워크는 다음과 같은 이점을 제공합니다:
개발 시간 단축: 검증된 구조와 기능 제공
유지보수 편의성: 표준화된 패턴과 구조
재사용 가능한 컴포넌트: 라이브러리보다 포괄적인 개발 환경
🔍 Spring Ecosystem
Spring Framework
모든 Spring 프로젝트의 핵심 기반이 되는 프레임워크
주요 기능:
의존성 주입 (Dependency Injection)
제어의 역전 (Inversion of Control)
Spring MVC 모델
데이터베이스 접근, 메시징, 트랜잭션 지원
Spring Boot
Spring Framework를 더 쉽고 빠르게 사용할 수 있도록 하는 도구
핵심 특징:
자동 구성 (Auto Configuration)
내장 웹 애플리케이션 서버 (Tomcat, Jetty 등)
단독 실행 가능한 JAR 파일 생성
복잡한 설정 과정 간소화
기타 Spring 프로젝트
Spring Data: 데이터 액세스 추상화
Spring Security: 보안 기능
Spring Cloud: 마이크로서비스 아키텍처 지원
✨ Spring Framework의 핵심 특징
1. 제어의 역전 (IoC, Inversion of Control)
객체의 생성과 관리를 개발자가 아닌 Spring Container가 담당
2. 의존성 주입 (DI, Dependency Injection)
객체 간의 의존 관계를 Spring이 자동으로 연결
3. 관점 지향 프로그래밍 (AOP)
횡단 관심사를 모듈화하여 코드의 중복을 줄임
4. MVC 패턴 지원
웹 애플리케이션 개발을 위한 Model-View-Controller 구조 제공
🚫 Spring Framework의 한계점
설정의 복잡성
XML 설정 파일의 복잡함
다양한 설정 옵션으로 인한 학습 곡선 증가
높은 초기 학습 난이도
개념 이해를 위한 많은 학습 시간 필요
다양한 기능 활용을 위한 깊은 이해 요구
의존성 관리의 어려움
라이브러리 간 호환성 문제
버전 충돌 해결의 복잡성
배포 환경 구성의 번거로움
별도의 웹 애플리케이션 서버 필요
복잡한 배포 과정
🎯 SpringBoot의 해결책
자동 설정 (Auto Configuration)
@SpringBootApplication // 이 하나의 애노테이션으로 모든 설정 완료!
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
내장 서버
Tomcat, Jetty, Undertow 등을 내장
별도의 서버 설치 없이 java -jar 명령으로 실행 가능
의존성 관리 간소화
<!-- 기존 Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.21</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.21</version>
</dependency>
<!-- ... 수많은 의존성들 -->
<!-- SpringBoot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
운영 환경 지원
Health Check 엔드포인트
Metrics 수집
외부 설정 관리 (application.properties/yml)
🏗️ SpringBoot의 핵심 개념
Starter Dependencies
목적별로 필요한 의존성을 묶어서 제공:
spring-boot-starter-web: 웹 애플리케이션 개발
spring-boot-starter-data-jpa: JPA를 이용한 데이터 액세스
spring-boot-starter-security: 보안 기능
spring-boot-starter-test: 테스트 환경
프로파일 (Profiles)
환경별 설정 관리:
# application-dev.yml
server:
port: 8080
logging:
level:
com.example: DEBUG
# application-prod.yml
server:
port: 80
logging:
level:
com.example: INFO
🎉 결론
Spring Framework는 자바 생태계의 핵심 프레임워크로서 강력한 기능을 제공하지만, 복잡한 설정과 높은 학습 곡선이라는 단점이 있었습니다.
SpringBoot는 이러한 문제점들을 해결하여:
⚡ 빠른 개발 시작: 최소한의 설정으로 프로젝트 시작
🔧 자동 구성: 관례를 따르는 설정 자동화
📦 간편한 배포: 내장 서버로 단독 실행 가능
🛠️ 생산성 향상: 비즈니스 로직에 집중 가능
Spring 생태계는 Spring Framework, SpringBoot, 그리고 다양한 서브 프로젝트들이 함께 구성하는 완성도 높은 개발 환경을 제공합니다.
📚 더 알아보기
공식 문서: spring.io
“Spring makes programming Java quicker, easier, and safer for everybody. Spring’s focus on speed, simplicity, and productivity has made it the world’s most popular Java framework.”
-
-
🏛️[SpringBoot] 스프링 부트의 핵심 개념`:` 제어의 역전(IoC) - XML 기반 구현
🏛️[SpringBoot] 스프링 부트의 핵심 개념: 제어의 역전(IoC) - XML 기반 구현
📖 개요
제어의 역전(IoC, Inversion of Control) 은 객체의 생성과 의존성 관리를 개발자가 아닌 Spring Container 가 담당하도록 하는 설계 원칙입니다. XML 설정 파일을 통해 IoC를 구현하는 전통적인 방법을 학습해보겠습니다.
🚨 기존 의존성 주입의 한계점
여전히 남은 문제점
이전에 의존성 주입을 통해 클래스 간 결합도를 낮췄지만, 여전히 수정이 필요한 부분이 있습니다:
public class Main {
public static void main(String[] args) {
CoffeeMaker coffeeMaker = new CoffeeMaker();
// 🚨 새로운 커피 머신이 추가될 때마다 이 부분을 수정해야 함
coffeeMaker.setCoffeeMachine(new DripCoffeeMachine());
coffeeMaker.makeCoffee();
// 다른 커피 머신으로 변경하려면 또 수정 필요
coffeeMaker.setCoffeeMachine(new EspressoMachine());
coffeeMaker.makeCoffee();
}
}
복잡한 의존성 관계에서의 문제점
// 실제 애플리케이션에서는 이런 복잡한 의존성 관계가 발생
UserService userService = new UserService();
PaymentService paymentService = new PaymentService();
EmailService emailService = new EmailService();
OrderService orderService = new OrderService();
// 의존성 주입
userService.setUserRepository(new UserRepository());
paymentService.setPaymentGateway(new StripePaymentGateway());
emailService.setEmailProvider(new GmailProvider());
orderService.setUserService(userService);
orderService.setPaymentService(paymentService);
orderService.setEmailService(emailService);
// 🚨 매번 이런 복잡한 설정 코드를 작성해야 함
🔄 제어의 역전(IoC) 개념
전통적 방식 vs IoC 방식
구분
전통적 방식
IoC 방식
객체 생성
개발자가 new 키워드로 직접 생성
프레임워크가 자동 생성
의존성 주입
개발자가 메서드 호출로 직접 주입
프레임워크가 자동 주입
흐름 제어
개발자가 직접 제어
프레임워크가 간접 제어
설정 방법
소스코드 내부에서 하드코딩
외부 설정 파일 또는 애노테이션
IoC의 핵심 아이디어
graph TB
A[개발자] -->|제어권 이양| B[Spring Container]
B -->|객체 생성| C[Bean Objects]
B -->|의존성 주입| D[Dependency Injection]
B -->|생명주기 관리| E[Lifecycle Management]
📄 XML 기반 IoC 구현
1단계: XML 스키마 준비
Spring Framework의 공식 XML 스키마를 사용합니다:
참조 링크: Spring XML Schemas
2단계: beans.xml 파일 생성
파일 위치: src/main/resources/beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 드립 커피 머신 Bean 정의 -->
<bean id="dripCoffeeMachine" class="com.example.demo.DripCoffeeMachine"/>
<!-- 에스프레소 머신 Bean 정의 -->
<bean id="espressoMachine" class="com.example.demo.EspressoMachine"/>
<!-- 커피 메이커 Bean 정의 및 의존성 주입 -->
<bean id="coffeeMaker" class="com.example.demo.CoffeeMaker" init-method="makeCoffee">
<property name="coffeeMachine" ref="espressoMachine"/>
</bean>
</beans>
3단계: 클래스 구조 정의
인터페이스
public interface CoffeeMachine {
String brew();
}
구현체들
public class EspressoMachine implements CoffeeMachine {
@Override
public String brew() {
return "Brewing coffee with Espresso Machine";
}
}
public class DripCoffeeMachine implements CoffeeMachine {
@Override
public String brew() {
return "Brewing coffee with Drip Coffee Machine";
}
}
CoffeeMaker 클래스
public class CoffeeMaker {
private CoffeeMachine coffeeMachine;
// Setter 메서드 (XML에서 property 주입을 위해 필요)
public void setCoffeeMachine(CoffeeMachine coffeeMachine) {
this.coffeeMachine = coffeeMachine;
}
// init-method로 지정될 메서드
public void makeCoffee() {
System.out.println(coffeeMachine.brew());
}
}
4단계: Spring Boot 애플리케이션 설정
@SpringBootApplication
@ImportResource("classpath:beans.xml") // XML 설정 파일 import
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
🧩 XML 설정 파일 구성 요소
<bean> 태그 속성들
속성
설명
예시
id
Bean의 고유 식별자
id="coffeeMaker"
class
Bean으로 생성할 클래스 (전체 패키지 경로)
class="com.example.demo.CoffeeMaker"
init-method
객체 생성 후 자동 실행할 메서드
init-method="makeCoffee"
destroy-method
객체 소멸 전 실행할 메서드
destroy-method="cleanup"
<property> 태그 - 의존성 주입
<!-- Setter 주입 -->
<bean id="coffeeMaker" class="com.example.demo.CoffeeMaker">
<property name="coffeeMachine" ref="espressoMachine"/>
<property name="maxCapacity" value="500"/>
</bean>
<!-- 생성자 주입 -->
<bean id="coffeeMaker" class="com.example.demo.CoffeeMaker">
<constructor-arg ref="espressoMachine"/>
<constructor-arg value="500"/>
</bean>
🚀 실행 흐름 분석
1. 애플리케이션 시작
SpringApplication.run(DemoApplication.class, args);
2. XML 파일 로딩
@ImportResource("classpath:beans.xml")
3. Spring Container의 작업 순서
Bean 정의 파싱: XML에서 Bean 정보를 읽어들임
객체 생성: 각 Bean 클래스의 인스턴스 생성
DripCoffeeMachine dripCoffeeMachine = new DripCoffeeMachine();
EspressoMachine espressoMachine = new EspressoMachine();
CoffeeMaker coffeeMaker = new CoffeeMaker();
의존성 주입: <property> 태그에 따라 의존성 주입
coffeeMaker.setCoffeeMachine(espressoMachine);
초기화 메서드 실행: init-method 실행
coffeeMaker.makeCoffee(); // 자동 실행
4. 실행 결과
Brewing coffee with Espresso Machine
✅ XML 기반 IoC의 장점
🎯 코드 변경 없는 설정 변경
<!-- 에스프레소 머신에서 드립 머신으로 변경하려면 XML만 수정 -->
<bean id="coffeeMaker" class="com.example.demo.CoffeeMaker" init-method="makeCoffee">
<property name="coffeeMachine" ref="dripCoffeeMachine"/> <!-- 여기만 변경! -->
</bean>
🏗️ 중앙집중식 설정 관리
모든 Bean 설정을 한 곳에서 관리
의존성 관계를 한눈에 파악 가능
환경별 설정 분리 용이
🔧 유연한 객체 생명주기 제어
<bean id="databaseConnection"
class="com.example.DatabaseConnection"
init-method="connect"
destroy-method="disconnect"
scope="singleton">
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
</bean>
⚠️ XML 기반 IoC의 한계점
1. 컴파일 타임 검증 불가
<!-- 오타가 있어도 실행 시점에만 에러 발생 -->
<bean id="coffeeMaker" class="com.example.demo.CoffeeMakr"> <!-- 오타! -->
<property name="coffeeMachin" ref="espressoMachine"/> <!-- 오타! -->
</bean>
2. IDE 지원 제한
자동완성, 리팩토링 지원 부족
클래스명 변경 시 XML 파일 수동 수정 필요
3. XML 파일 복잡성 증가
대규모 프로젝트에서는 XML 파일이 매우 복잡해질 수 있습니다.
🆚 현대적 접근법과의 비교
Annotation 기반 설정 (현재 권장 방식)
@Component
public class EspressoMachine implements CoffeeMachine {
// 구현
}
@Component
public class CoffeeMaker {
private final CoffeeMachine coffeeMachine;
@Autowired
public CoffeeMaker(CoffeeMachine coffeeMachine) {
this.coffeeMachine = coffeeMachine;
}
@PostConstruct
public void makeCoffee() {
System.out.println(coffeeMachine.brew());
}
}
Java Config 기반 설정
@Configuration
public class CoffeeConfig {
@Bean
public CoffeeMachine espressoMachine() {
return new EspressoMachine();
}
@Bean
public CoffeeMaker coffeeMaker(CoffeeMachine coffeeMachine) {
CoffeeMaker maker = new CoffeeMaker();
maker.setCoffeeMachine(coffeeMachine);
return maker;
}
}
🎯 언제 XML 설정을 사용할까?
적합한 경우
레거시 시스템 통합: 기존 XML 기반 설정과의 호환성 필요
외부 라이브러리 설정: 소스 코드 수정이 불가능한 서드파티 라이브러리
런타임 설정 변경: 애플리케이션 재배포 없이 설정 변경 필요
현재 권장 방식
Annotation 기반: @Component, @Service, @Repository
Java Config: @Configuration, @Bean
Spring Boot Auto Configuration: @SpringBootApplication
💡 실무 팁
XML과 Annotation 혼용
@SpringBootApplication
@ImportResource("classpath:legacy-beans.xml") // 레거시 XML 설정
public class ModernApplication {
// 현대적 애노테이션 기반 코드
}
Profile별 XML 설정
<!-- beans-dev.xml -->
<beans profile="dev">
<bean id="dataSource" class="com.example.DevDataSource"/>
</beans>
<!-- beans-prod.xml -->
<beans profile="prod">
<bean id="dataSource" class="com.example.ProdDataSource"/>
</beans>
🎓 학습 포인트
핵심 개념
제어의 역전: 객체 생성과 관리 책임을 프레임워크에 위임
외부 설정: 코드 변경 없이 설정 파일만으로 동작 변경 가능
생명주기 관리: init-method, destroy-method를 통한 객체 생명주기 제어
다음 학습 단계
Annotation 기반 IoC: @Component, @Autowired 등
Java Config: @Configuration, @Bean
Spring Boot Auto Configuration: 자동 설정의 원리
Bean Scope: Singleton, Prototype, Request, Session
XML 기반 IoC는 Spring Framework의 기초를 이해하는 데 중요한 개념이지만, 현재는 더 간편하고 타입 안전한 Annotation 기반 설정을 주로 사용합니다.
Touch background to close