IoC(제어의 역전)는 Spring 프레임워크의 가장 근본적인 설계 철학입니다.
전통적인 방식: 개발자가 직접 객체를 생성(new MyService())하고, 의존성을 연결하며 프로그램의 흐름을 제어합니다. (제어권이 개발자에게 있음)
IoC 방식: 객체의 생성, 생명주기 관리, 의존성 연결 등 모든 제어권이 개발자로부터 프레임워크(Spring 컨테이너)로 넘어간(역전된) 것을 의미합니다.
DI(의존성 주입)는 IoC를 구현하는 구체적인 방법입니다.
장점:
MySqlRepository → PostgresRepository)Spring의 DI 방법:
final 키워드로 불변성을 보장하고, 의존성 누락을 방지하며, 순환 참조를 조기에 발견할 수 있습니다.Spring 컨테이너 (IoC 컨테이너):
Bean:
@Component 어노테이션(또는 이를 상속하는 @Service, @Repository, @Controller 등)을 클래스에 붙여, 해당 클래스의 객체를 Bean으로 등록해달라고 Spring에 요청합니다.@Autowired가 붙은 곳에 주입해줍니다.AOP는 OOP를 보완하는 프로그래밍 패러다임으로, 횡단 관심사(Cross-cutting Concerns)를 분리하여 코드의 모듈성을 높이는 기술입니다.
횡단 관심사: 애플리케이션의 여러 비즈니스 로직(핵심 관심사)에 걸쳐 공통적으로 나타나는 부가 기능을 의미합니다. (e.g., 로깅, 트랜잭션, 보안, 예외 처리)
AOP의 해결책: 이러한 횡단 관심사를 "Aspect"라는 별도의 모듈로 분리하여, 핵심 비즈니스 로직에는 영향을 주지 않으면서 필요한 곳(Pointcut)에 동적으로 적용(Weaving)합니다.
Spring의 @Transactional: Spring AOP의 가장 대표적인 활용 사례입니다. 개발자는 비즈니스 로직에만 집중하고 @Transactional 어노테이션만 붙이면, Spring이 AOP를 통해 해당 메서드의 시작과 끝에 트랜잭션 시작/커밋/롤백이라는 부가 기능(Aspect)을 동적으로 적용해줍니다.
PSA는 Spring 프레임워크가 제공하는 또 다른 중요한 가치로, 특정 기술에 종속되지 않는 일관된 방식의 API를 제공하는 설계 원칙입니다.
문제점: 세상에는 다양한 기술 구현체들이 존재합니다. 예를 들어, 데이터베이스 트랜잭션을 관리하는 방식은 JPA, JDBC, Hibernate마다 모두 다릅니다. 만약 JPA를 사용하다가 JDBC로 기술을 변경하면, 트랜잭션과 관련된 모든 코드를 새로 작성해야 합니다.
Spring의 해결책 (PSA): Spring은 이러한 기술들의 세부 구현을 추상화하고, 개발자에게는 일관된 API를 제공합니다.
@Transactional: 개발자는 데이터 접근 기술이 JPA이든 JDBC이든 상관없이, @Transactional이라는 동일한 어노테이션을 사용하여 트랜잭션을 관리할 수 있습니다. 내부적으로는 Spring이 각 기술에 맞는 트랜잭션 관리자를 알아서 동작시켜 줍니다.@Cacheable): 캐시 기술이 Redis이든 Caffeine이든 상관없이, @Cacheable이라는 동일한 어노테이션으로 캐싱을 적용할 수 있습니다.@RabbitListener): 메시지 큐 기술이 RabbitMQ이든 다른 AMQP 구현체이든 상관없이, 동일한 어노테이션으로 메시지를 소비할 수 있습니다.장점: PSA 덕분에 개발자는 특정 기술의 세부적인 API를 깊이 알지 못해도, Spring이 제공하는 일관된 방법으로 기술을 사용할 수 있습니다. 또한, 기반 기술이 변경되더라도 비즈니스 코드의 변경을 최소화할 수 있어 유연하고 확장성 있는 애플리케이션을 만들 수 있습니다.