- Published on
- •👁️
Spring Framework
- Authors

- Name
- River
상세 설명
Spring Framework
- Java 기반 엔터프라이즈 애플리케이션 개발을 위한 포괄적인 프레임워크
- 엔터프라이즈 애플리케이션 = 기업용 대규모 시스템
- 은행, 쇼핑몰, 병원 시스템 등
- 엔터프라이즈 애플리케이션 = 기업용 대규모 시스템
- 핵심 기능
- IoC (Inversion of Control)
- DI (Dependency Injection)
- AOP (Aspect-Oriented Programming)
- 높은 유연성과 확장성을 제공하지만, 초기 설정이 복잡하고 러닝 커브가 높다.
- Spring Framework는 아주 오래되고 많이 사용되는 Framework로 Jenkins, Docker, Kubernetes 등 배포 도구들과의 연동이 잘 되어있다.
Spring Boot
- Spring Framework + Tomcat 내장 서버
- Spring Boot는 Spring Framework 대체 프레임워크가 아니라, Spring Framework 위에 구축된 도구
Spring Framework의 기능들을 사용하되, 복잡한 설정과 시작 과정을 단순화한 것으로
빠른 개발과 배포를 위한 도구와 기능들을 제공한다.
- 핵심 기능
- 자동 설정 (Auto Configuration)
- 스타터 의존성 (Starter Dependencies)
- 내장 서버 (Embedded Server)
- 편의 기능 (DevTools, Actuator 등)
자동 설정 (Auto Configuration)
Spring
@Configuration @EnableWebMvc @EnableTransactionManagement @ComponentScan(basePackages = "com.example") public class WebConfig implements WebMvcConfigurer { @Bean public DataSource dataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db"); dataSource.setUsername("user"); dataSource.setPassword("password"); dataSource.setMaximumPoolSize(20); // 수십 줄의 설정... return dataSource; } }- Spring Framework는 복잡한 수동 설정이 필요하다.
Spring Boot
- ClassPath를 기반으로 필요한 Bean들을 자동 등록
@SpringBootApplication에노테이션으로 간단하게 활성화
spring: datasource: url: jdbc:mysql://localhost:3306/dbapplication.ymlorapplication.properties만 있으면 된다
내장 서버 (Embedded Server)
- Spring
- Tomcat 서버 별도 설치
- WAR 파일 생성
- Tomcat에 배포
- 서버 시작
- Spring Boot
- Tomcat, Jetty, Undertow를 내장하여 별도 서버 설치 불필요
- jar 파일 하나로 어디서든 실행 가능
스타터 의존성 (Starter Dependencies)
Spring
dependencies { implementation 'org.springframework:spring-core:5.3.21' implementation 'org.springframework:spring-web:5.3.21' implementation 'org.springframework:spring-webmvc:5.3.21' }- Spring은 라이브러리 하나씩 의존성이 되어 있다.
- Spring Boot의 스타터 의존성 (Starter Dependencies)
관련된 라이브러리들을 묶어서 제공
⇒ 버전 충돌 걱정 없이 기능 단위로 의존성 관리
spring-boot-starter-web,spring-boot-starter-data-jpa등dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' }- 이 하나에 core, beans, context, web, webmvc 모두 포함!
Actuator
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
management:
endpoints:
web:
exposure:
include: health,info,metrics
- 애플리케이션 상태 모니터링 REST API 제공
- 복잡한 설정 없이 의존성만 추가하면 바로 사용 가능
DevTools
- Spring Boot 전용 (Spring Framework에는 없음)
- 코드 수정 시 자동 재시작
- 브라우저 자동 새로고침
- 템플릿 캐시 비활성화
@SpringBootApplication 에노테이션
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan@Configuration- 설정 클래스라는 표시
@EnableAutoConfiguration- 자동 설정 활성화 ⇒ ClassPath의 외부 라이브러리를 보고 자동으로 Bean 생성
@ComponentScan- 내 클래스 파일에서
@Component등 스캔해서 Bean 등록
- 내 클래스 파일에서
주요 차이점
| 항목 | Spring Framework | Spring Boot |
|---|---|---|
| 설정 방식 | XML or Java Config로 모든 Bean 직접 정의 | application.yml + 자동 설정 |
| 의존성 관리 | 개별 라이브러리 + 버전 충돌 관리 | 스타터로 호환 버전 일괄 제공 |
| 서버 실행 | 외부 Tomcat + WAR 배포 | 내장 서버 + JAR 실행 |
| 개발 도구 | 별도 구성 필요 | DevTools, Actuator 기본 제공 |
| 프로젝트 시작 | 수십 개 설정 파일 작성 | spring initializr로 즉시 시작 |
상세 설명
Spring Bean이란?
Spring IoC 컨테이너에 의해 관리되는 객체
컨테이너가 Bean의 생명주기(생성, 초기화, 소멸)를 담당
애플리케이션의 핵심 구성 요소들을 Spring이 관리하는 형태
내부 클래스 파일은
@Component,@Service,@Repository,@Controller등으로 등록하고외부 라이브러리의 경우
@Configuration의@Bean메서드로 등록
객체를 Bean으로 관리하는 이유
객체 생명주기 자동 관리
@Component public class DatabaseConnection { @PostConstruct public void init() { // 초기화 로직 (컨테이너가 자동 호출) } @PreDestroy public void cleanup() { // 정리 로직 (컨테이너가 자동 호출) } }- 개발자가 직접 객체를 생성하고 소멸시킬 필요가 없다
- 애플리케이션 시작/종료 시 자동으로 초기화/정리 작업 수행
의존성 주입 (Dependency Injection, DI)
@Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } }- 객체 간의 의존 관계를 Spring이 자동으로 설정
- Spring이 자동 주입
- 결합도 감소, 테스트 용이성 향상
- 객체 간의 의존 관계를 Spring이 자동으로 설정
싱글톤 패턴 자동 적용
@Component public class ConfigurationManager { // Spring이 기본적으로 싱글톤으로 관리 // 애플리케이션 전체에서 하나의 인스턴스만 존재 }- 기본적으로 싱글톤 스코프로 관리되어 메모리 효율성 제공
- 여러 곳에서 동일한 인스턴스 사용 보장
AOP (Aspect-Oriented Programming) 적용
@Service @Transactional public class OrderService { public void processOrder(Order order) { // 비즈니스 로직만 작성 // 트랜잭션 시작/커밋/롤백은 Spring이 자동 처리 } }- Bean으로 관리되는 객체에만 AOP 적용 가능
@Transactional⇒ Spring이 트랜잭션 프록시 생성- 트랜잭션 시작/커밋/롤백은 Spring이 자동 처리
- 트랜잭션, 보안, 로깅 등을 투명하게 적용
프록시를 통한 기능 확장
@Component public class CacheableService { @Cacheable("users") public User findUser(Long id) { // 실제 조회 로직 return userRepository.findById(id); } }@Cacheable("users")⇒ Spring이 캐싱 프록시 생성
- Spring에서 Bean으로 관리한다는 것은 단순히 객체를 생성하는 것이 아니라, 의존성 주입, 생명주기 관리, AOP 적용 등 Spring 프레임워크의 모든 기능을 활용할 수 있게 하는 것이다. 이를 통해 개발자는 비즈니스 로직에만 집중할 수 있다.
Bean Scope와 Lifecycle
다양한 Bean Scope 지원
@Component @Scope("singleton") *// 기본값, 애플리케이션당 하나* public class SingletonBean { } @Component @Scope("prototype") *// 요청할 때마다 새 인스턴스* public class PrototypeBean { } @Component @Scope("request") *// HTTP 요청당 하나 (웹 환경)* public class RequestScopedBean { }@Scope("singleton")- default 값으로 생략 시 기본이 싱글톤 스코프이다.
- 이러한 스코프에 따라 생명주기가 달라진다.
Bean 생명주기 콜백
@Component public class LifecycleBean { *// 1. 생성자 호출* public LifecycleBean() { System.out.println("1. 생성자 호출"); } *// 2. 의존성 주입 완료 후* @PostConstruct public void init() { System.out.println("2. 초기화 메서드 호출"); } *// 3. 컨테이너 종료 시 (애플리케이션 종료 시)* @PreDestroy public void destroy() { System.out.println("3. 소멸 메서드 호출"); } }@Component이므로 기본이 싱글톤 스코프이다.- 이 경우 생성자,
init(),destroy()딱 1번만 실행한다.
- 애플리케이션 시작 시, 생성자가 호출되고
- 이후 의존성 주입 완료 후, 초기화 메서드가 호출된다.
- 애플리케이션 실행
- 애플리케이션 종료 직전
destroy()가 실행된다. - 애플리케이션 종료
- 이 경우 생성자,
- 콜백이란, Spring이 특정 시점에 자동으로 호출해주는 메서드
- Scope
- Bean이 몇 개까지 만들어지고, 언제까지 살아있는지 정하는 규칙
- 즉, Singleton Scope인 경우 애플리케이션 전체에서 하나의 객체만 만들도록 설정하는 것
Bean 관리의 실무적 이점
- 설정의 중앙화
@Configuration public class AppConfig { @Bean @Profile("dev") public DataSource devDataSource() { return new H2DataSource(); } @Bean @Profile("prod") public DataSource prodDataSource() { return new PostgreSQLDataSource(); } }- 환경별 설정을 중앙에서 관리
- 프로파일에 따른 다른 Bean 주입 가능
- 테스트 지원 (중요!)
@Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public User createUser(String name) { return userRepository.save(new User(name)); } } @SpringBootTest class UserServiceTest { @MockBean private UserRepository userRepository; // Mock Bean @Autowired private UserService userService; @Test void testCreateUser() { when(userRepository.save(any())).thenReturn(savedUser); // 테스트 수행 } }- 예를 들어, Bean으로 관리되는 Service를 테스트하는 경우, 테스트 시 쉽게 Mock Bean으로 쉽게 교체할 수 있다.
- 즉,
@MockBean을 설정만 하면@Autowired시 Mock Repository가 주입된 UserService 객체가 들어온다.
- 모니터링과 관리
@Component public class HealthChecker { @EventListener public void handleContextRefresh(ContextRefreshedEvent event) { System.out.println("애플리케이션 컨텍스트 초기화 완료"); } }- Spring Boot Actuator를 통한 Bean 정보 조회
- 애플리케이션 상태 모니터링
Bean으로 관리하지 않는 객체들
- 일반적인 데이터 객체 (ex. DTO, Entity)
@Entity public class User { private String email;- Bean으로 관리하지 않음
- Utility 클래스의 static 메서드
public class StringUtils { public static boolean isEmpty(String str) { return str == null || str.isEmpty(); } }- Bean으로 관리할 필요가 없다.
상세 설명
의존성 주입(Dependency Injection)이란?
- 객체가 필요로 하는 의존성(다른 객체)을 외부에서 주입 받는 디자인 패턴
- 객체가 직접 의존성을 생성하는 대신, 외부(컨테이너)에서 생성된 객체를 주입 받는 것
- 제어의 역전(IoC, Inversion of Control)의 구체적인 구현 방법 중 하나
- 객체 간의 결합도를 낮추고, 코드의 유연성과 테스트 용이성을 향상
의존성 주입(DI) 전후 차이
- 이전
public class OrderService { private EmailSender emailSender = new EmailSender(); // 직접 생성 private SmsNotifier smsNotifier = new SmsNotifier(); // 직접 생성 public void processOrder(Order order) { // 주문 처리 로직 emailSender.sendOrderConfirmation(order); smsNotifier.sendNotification(order); } }- 문제점
OrderService가 구체적인 구현체에 강한 결합
⇒ 테스트 시 실제 이메일이 발송되거나 SMS가 전송될 수 있음
다른 알림 방식으로 변경하려면 코드 수정 필요 (OCP 위반)
단위 테스트가 어려움
- 문제점
- 이후
@Service public class OrderService { private final NotificationService notificationService; // 생성자 주입 public OrderService(NotificationService notificationService) { this.notificationService = notificationService; } public void processOrder(Order order) { // 주문 처리 로직 notificationService.sendOrderConfirmation(order); } } @Component public class EmailNotificationService implements NotificationService { @Override public void sendOrderConfirmation(Order order) { // 이메일 발송 로직 } }- 생성자를 통해 의존성을 주입 받는다.
- 약한 결합
- Spring의 경우, IoC 컨테이너로 객체 생성 및 의존성 주입도 자동화할 수 있다.
- 테스트 시 Mock 객체를 활용할 수 있어 테스트가 용이하다.
- 인터페이스까지 활용한다면 다른 기능으로 변경 시 쉽게 변경할 수 있다. (OCP 준수)
- 생성자를 통해 의존성을 주입 받는다.
@Autowired 동작 원리
@Service
public class OrderService {
private final PaymentService paymentService;
**public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
- 타입 기반으로 Bean을 찾아서 주입
- 같은 타입의 Bean이 여러 개인 경우
@Qualifier사용 @Autowired생략 가능 (생성자가 하나인 경우)
권장되는 의존성 주입 방식
- 생성자 + Lombok
@RequiredArgsConstructor @Service public class OrderService { private final PaymentService paymentService; }- Spring Boot에서는 생성자가 하나인 경우 @Autowired를 생략할 수 있으며, Lombok의 @RequiredArgsConstructor를 사용하면 final 필드에 대한 생성자를 자동 생성하여 더욱 간편하게 의존성 주입을 구현할 수 있다.
- 장점
- 불변성 보장
- 테스트 시 의존성 주입이 쉽다.
- 순환 참조 즉시 감지
의존성 주입의 장점
- 낮은 결합도 (Low Coupling)
- 인터페이스에 의존하여 구현체 변경이 용이
- 객체 간의 직접적인 의존성 제거
- 재사용성과 유지보수성 향상
- 동일한 컴포넌트를 다양한 환경에서 재사용
- 코드 변경 없이 다른 구현체로 교체 가능
높은 테스트 용이성
@SpringBootTest void orderServiceTest() { ** @MockBean private PaymentService paymentService; @Autowired private OrderService orderService; @Test void orderServiceTest() { // 테스트 로직 } **}
의존성 주입 주의사항
- 순환 참조 (Circular Dependency)
@Service public class ServiceA { public ServiceA(ServiceB serviceB) { ... } *// A → B* } @Service public class ServiceB { public ServiceB(ServiceA serviceA) { ... } *// B → A (순환 참조)* }- 생성자 주입 시 애플리케이션 시작 시점에 오류 발생
@Qualifier를 통한 Bean 선택public interface NotificationService { ... } @Component("emailNotification") public class EmailNotificationService implements NotificationService { ... } @Component("smsNotification") public class SmsNotificationService implements NotificationService { ... } @Service @RequiredArgsConstructor public class OrderService { @Qualifier("emailNotification") private final NotificationService notificationService; }- NotificationService 구현체가 하나가 아니라면,
@Qualifier로 구현체를 특정할 수 있다.
- NotificationService 구현체가 하나가 아니라면,
실무에서의 패턴
- 프로파일별 Bean 설정
@Service @Profile("dev") public class MockEmailService implements EmailService { ... } @Service @Profile("prod") public class RealEmailService implements EmailService { ... }
상세 설명
스테레오타입 애노테이션(Stereotype Annotation)이란?
- Spring에서 클래스의 역할을 명시하고 Bean으로 등록하기 위해 사용하는 애노테이션들
- 모두 @Component를 기반으로 하는 특수화된(specialized) 애노테이션
- 최상위인
@Component를 다른 애노테이션이 상속 받고 있다.
- 최상위인
- 컴포넌트 스캔(@ComponentScan)을 통해 자동으로 Bean으로 등록
컴포넌트 스캔은 @SpringBootApplication 애노테이션으로 활성화된다.
@SpringBootApplication= @Configuration + @ComponentScan + @EnableAutoConfiguration
등록된 Bean은 의존성 주입에 사용된다.
- 코드의 가독성과 유지보수성을 향상시키고, 계층별 역할을 명확히 구분한다.
- 종류
- @Component
- 일반적인 스프링 컴포넌트 (최상위)
- @Service
- Service Layer (비즈니스 로직 계층)
- @Repository
- DAO Layer (DB 접근 계층)
- @Controller
- Controller Layer (웹 계층)
- @Configuration
- 설정 파일,
@Bean을 수동 등록할 때 사용하는 클래스
- 설정 파일,
- @RestController 등
- @Component
- @Entity
- Spring이 아닌 JPA(Hibernate)의 에노테이션이다.
- Java Persistence API(JPA)의 일부로, DB 테이블과 매핑하기 위해 사용
@Component
@Component
public class EmailSender {
public void sendEmail(String message) {
// 이메일 전송 로직
}
}
- 가장 기본적인 스테레오타입 애노테이션
- 특별한 역할이 없는 일반적인 Spring Bean을 등록할 때 사용
- 다른 스테레오타입 애노테이션들의 기반이 되는 메타 애노테이션
- 사용
- Utility 클래스, Helper 클래스 등에 주로 사용
@Controller
@Controller
public class UserController {
@RequestMapping("/users")
public String getUsers(Model model) {
// 사용자 목록 조회 로직
return "users";
}
}
Spring MVC의 컨트롤러 계층에 사용
웹 요청(HTTP 요청)을 처리하고 응답을 생성하는 역할
@RequestMapping,@GetMapping등과 함께 사용하여 URL 매핑Spring MVC에서 Handler Mapping 시 컨트롤러로 인식
즉, 즉, 해당 클래스가 HTTP 요청을 처리할 수 있는 컨트롤러로 인식되도록 해준다.
- Handler Mapping
- Spring MVC가 HTTP 요청을 처리할 때, 어떤 메서드가 이 요청을 처리할지 결정
- Handler Mapping
@RestController는 @Controller + @ResponseBody의 조합으로, JSON/XML 등의 데이터를 직접 반환하는 RESTful API 컨트롤러에 사용됩니다.
Spring MVC 동작 구조
- 클라이언트가 요청을 보냄 (
GET /users/1) - DispatcherServlet이 요청을 받음
HandlerMapping이 요청 URL에 맞는 컨트롤러 메서드를 찾음HandlerAdapter가 해당 메서드 실행- 컨트롤러 종류에 따라 html 렌더링이나 JSON 반환
- 클라이언트가 요청을 보냄 (
HandlerMapping이 찾을 때 @Controller로 컨트롤러를 인식
@Service
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public User createUser(User user) {
// 비즈니스 로직 처리
validateUser(user);
return userRepository.save(user);
}
}
- 비즈니스 로직을 처리하는 서비스 계층에 사용
- 서비스 계층
- 트랜잭션 처리, 비즈니스 로직 구현 등
- 서비스 계층
- @Component와 기능적으로 동일하지만, 비즈니스 로직의 역할을 명시
- 코드의 가독성과 유지보수성 향상
@Repository
@Repository
public class UserRepositoryImpl implements UserRepository {
@PersistenceContext
private EntityManager entityManager;
public User findById(Long id) {
return entityManager.find(User.class, id);
}
}
- 데이터 접근 계층(DAO, Data Access Object)에 사용
- 데이터베이스와의 상호작용을 담당
- 특별한 기능
- 데이터 접근 계층에서 발생하는 예외를 Spring의 DataAccessException으로 자동 변환
- JPA, MyBatis, JDBC 등과 함께 사용
@Repository의 예외 변환 기능은 Spring AOP를 통해 구현됩니다. 데이터베이스별로 다른 예외들을 Spring의 일관된 예외 계층구조로 변환하여 데이터베이스 벤더에 독립적인 코드를 작성할 수 있게 해줍니다.
계층 구조 (Layered Architecture)
- Controller Layer
- 클라이언트 요청을 받아 응답 처리
- 요청 데이터 검증 및 변환
- 적절한 Service 메서드 호출
- Service Layer
- 비즈니스 로직 처리
- 트랜잭션 정의
- 여러 Repository 조합하여 복합적인 비즈니스 기능 제공
- Repository Layer
- DBMS와의 상호작용
- CRUD 연산 수행
실무에서의 사용 패턴
@Controller
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@PostMapping("/orders")
public String createOrder(@ModelAttribute Order order) {
orderService.processOrder(order);
return "redirect:/orders";
}
}
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class OrderService {
private final OrderRepository orderRepository;
public void processOrder(Order order) {
// 비즈니스 로직
order.calculateTotal();
orderRepository.save(order);
}
}
@Repository
public class OrderRepository {
@PersistenceContext
private EntityManager em;
public Order save(Order order) {
em.persist(order);
return order;
}
}
상세 설명
AutoConfiguration이란?
Spring Boot가 제공하는 자동 설정 기능으로, Classpath에 존재하는 외부 라이브러리와 설정 정보를 기반으로 필요한 Bean을 자동으로 등록
개발자가 명시적으로 설정하지 않은 부분을 Spring Boot가 관례에 따라 자동으로 구성
"Convention over Configuration" 철학을 구현한 핵심 기능
⇒ 명시적으로 다 설정하지 않아도, 일반적인 관례를 기본값으로 제공하겠다.
@SpringBootApplication 애노테이션에 포함된
@EnableAutoConfiguration을 통해 활성화할 수 있다.
- Classpath란
- JVM이
.class파일을 찾기 위해 검색하는 경로들의 집합- 컴파일 결과 폴더 (
/bin,/build/classes,/target/classes) - JAR 파일
- 라이브러리 디렉토리
- src/main/resources 폴더 (
application.yml등)
- 컴파일 결과 폴더 (
- JVM이
AutoConfiguration 동작 과정
- 1단계 : AutoConfigurationImportSelector 실행
@EnableAutoConfiguration이 @Import(AutoConfigurationImportSelector.class)를 통해 실행- AutoConfigurationImportSelector 클래스
package: org.springframework.boot.autoconfigure ... public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 1. 메타데이터 로드 AutoConfigurationMetadata metadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); // 2. 자동 설정 엔트리 가져오기 AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(metadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { // 3. 후보 설정 클래스들 가져오기 (여기서 파일 읽기!) List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 4. 중복 제거, exclude 처리, 필터링 configurations = removeDuplicates(configurations); // 5. 최종 결과 반환 return new AutoConfigurationEntry(configurations, exclusions); } }selectImports()메서드가 핵심 진입점 역할 ⇒getAutoConfigurationEntry()
getCandidateConfigurations()메서드로 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일 읽기(Spring Boot 2.7 이상)
spring-boot-autoconfigure 라이브러리(JAR)의 AutoConfiguration.imports 파일에서 미리 정의된 100여 개의 자동 설정 클래스들 목록 획득
중복 제거, exclude 목록 처리, 필터링 수행
Ex. org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
- 2단계 : 각 자동 설정 클래스 처리
1단계에서 가져온 자동 설정 클래스들을 하나씩 처리
각 자동 설정 클래스에 대해 조건부 애노테이션 평가 (
@ConditionalOnClass,@ConditionalOnMissingBean등)⇒ Classpath에 특정 라이브러리가 존재하는지, 특정 Bean이 이미 등록되어 있는지 등을 검사
@EnableConfigurationProperties가 있는 클래스들은application.yml값을 Properties 객체로 바인딩조건을 만족하는 경우에만 Bean 등록
Ex. 예시
@Configuration(proxyBeanMethods = false) @ConditionalOnClass({EntityManager.class}) @ConditionalOnMissingBean(DataSource.class) @EnableConfigurationProperties(JpaProperties.class) // yml 바인딩 public class HibernateJpaAutoConfiguration { // 조건 만족 시 EntityManager 등 Bean 등록 }JPA 의존성을 넣지 않는 경우
⇒
EntityManager클래스가 classpath에 없으면 조건부 애노테이션에 따라, JPA 설정을 건들이지 않는다.
- 3단계 : Bean 등록 및 우선순위 처리
- 조건을 만족하는 자동 설정 클래스들이 실행되어 필요한 Bean들을 Spring 컨테이너에 등록
- 사용자가 정의한 Bean이 우선순위를 가지며, 자동 설정 Bean을 오버라이드할 수 있다.
주요 조건부 어노테이션
- 조건부 애노테이션이란?
- Bean 등록 또는 설정 적용 여부를 “조건부로 제어”하는 기능
- 자동 설정이 무조건 적용되지 않고, 상황에 따라 동적으로 적용 여부를 판단하기 위함
@Conditiona
@Conditional(MyCondition.class)- Spring의 기본형 조건부 애노테이션
- Condition 인터페이스 구현
- Spring Boot는 이것을 추상화한 특수 조건 애노테이션들을 제공한다.
- 모두
@Conditional을 내부적으로 사용한다.
- 모두
- @ConditionalOnClass
@ConditionalOnClass({DataSource.class, JdbcTemplate.class}) public class DataSourceAutoConfiguration { ... }- 특정 클래스가 Classpath에 존재할 때만 실행
- 즉, Classpath의
.class,-jar파일을 보고 조건에 해당하는 클래스가 있는지 판단한다.
- @ConditionalOnMissingBean
@ConditionalOnMissingBean(DataSource.class) @Bean public DataSource dataSource() { ... }- 특정 타입의 Bean이 없을 때만 실행
- @ConditionalOnProperty
@ConditionalOnProperty(name = "spring.datasource.url")- 특정 프로퍼티 값에 따라 실행
application.yml에 해당 프로퍼티가 존재하고 값이 설정되어 있을 때만 자동 설정 적용
@ConfigurationProperties
@Configuration
@ConditionalOnClass({DataSource.class, JdbcTemplate.class})
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DataSourceProperties properties) {
return DataSourceBuilder.create()
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword())
.build();
}
}
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {
private String url;
private String username;
private String password;
// getter, setter...
}
- @ConfigurationProperties와 AutoConfiguration의 관계
- AutoConfiguration에서
application.yml프로퍼티를 Java 객체로 바인딩하는 핵심 메커니즘 @EnableConfigurationProperties를 통해 프로퍼티 클래스를 Bean으로 등록- 예시
application.yml에spring.datasource.url=jdbc:mysql://localhost/test설정- DataSourceProperties 객체의
url필드에 자동으로 바인딩 - AutoConfiguration에서 이 객체를 주입 받아 DataSource Bean 설정에 사용
- AutoConfiguration에서
대표적인 AutoConfiguration 예시
- DataSourceAutoConfiguration
- H2, MySQL 등의 데이터베이스 드라이버가 Classpath에 있으면 자동으로 DataSource Bean 생성
- application.yml(properties)의
spring.datasource.*프로퍼티를 읽어 설정
- JpaRepositoriesAutoConfiguration
- Spring Data JPA가 Classpath에 있으면 JPA Repository 스캔 및 등록
- EntityManager, TransactionManager 등을 자동 구성
- WebMvcAutoConfiguration
- Spring Web MVC 의존성이 있으면 DispatcherServlet, ViewResolver 등을 자동 설정
사용자 정의 설정
- 특정 자동 설정 제외
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class MyApplication { ... }exclude = {DataSourceAutoConfiguration.class}
- 사용자 정의 Bean으로 오버라이드
@Configuration public class CustomDataSourceConfig { @Bean @Primary public DataSource customDataSource() { // 사용자 정의 DataSource } }
AutoConfiguration의 장점
- 빠른 개발 시작
- 최소한의 설정으로 애플리케이션 실행 가능
- 검증 완료
- 설정되는 것은 Spring 팀이 검증한 설정들이다.
- 유연성
- 필요에 따라 자동 설정을 부분적으로 오버라이드하거나 완전히 제외 가능
- 유지보수성
- 라이브러리 업그레이드 시 설정 변경이 자동으로 반영