스프링 프레임워크(Spring Framework)
자바(Java) 기반의 애플리케이션 프레임워크
엔터프라이즈급 애플리케이션 개발을 위해 다양한 기능을 제공합니다.
자바 언어를 이용해 엔터프라이즈급 개발을 편리하게 만들어주는 오픈소스 경량급 애플리케이션 프레임워크로 불립니다.
제어 역전(IoC)
스프링(Spring)의 IoC(Inversion of Control)는 스프링 프레임워크의 핵심 개념 중 하나로, 객체 지향 프로그래밍에서의 제어 흐름을 바꾸는 디자인 원칙 중 하나입니다.
IoC의 핵심 아이디어는 "제어의 역전(Inversion of Control)"이라는 개념입니다. 객체의 생성, 생명주기의 관리, 의존성 주입 등을 스프링 컨테이너가 담당하게 되어 있습니다. 이는 개발자가 직접 흐름을 제어하는 것이 아니라, 프레임워크가 컨트롤의 주도권을 가져가게 되어 있다는 것을 의미합니다.
객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것을 제어 역전이라하고, 이를 통해 의존성 주입(DI, Dependency Injection), 관점 지향 프로그래밍(AOP, Aspect-Oriented Programming)등이 가능해집니다.
의존성 주입(Dependency Injection)
제어의 역전 방법 중 하나로, 객체가 필요로 하는 의존 객체를 외부에서 주입하는 방식을 의미합니다.
의존성 주입 방식
스프링은 생성자 주입, setter 주입, 인터페이스 주입 등 다양한 방식으로 의존성 주입을 지원합니다.
생성자 사용
import com.wikibooks.chapter1.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DIController {
MyService myService;
@Autowired
public DIController(MyService myService) {
this.myService = myService;
}
@GetMapping("/di/hello")
public String getHello() {
return myService.getHello();
}
}
스프링 4.3 이후 버전은 생성자를 통해 @Autowired 어노테이션을 생략할 수 있습니다.
스프링 공식 문서에서 권장하는 의존성 주입방법은 생성자를 통해 의존성을 주입받는 방식입니다.
(의도적으로 객체 초기화 방지)
필드 객체 선언
import com.wikibooks.chapter1.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FieldInjectionController {
@Autowired
private MyService myService;
}
setter 메서드 사용
import com.wikibooks.chapter1.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SetterInjectionController {
MyService myService;
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
}
관점 지향 프로그래밍(AOP)
관점 지향 프로그래밍(AOP)은 여러 비즈니스 로직에서 반복되는 부가 기능을 하나의 공통 로직으로 처리하도록 모듈화에 삽입하는 방식을 AOP라고 합니다.
AOP는 이러한 부가 기능을 모듈화하여 쉽게 재사용하고, 모듈화를 향상시켜 핵심 비즈니스 로직과의 결합도를 낮추는 것을 목표로 합니다. AOP는 코드의 재사용성과 유지보수성을 향상시키는 데 기여합니다.
AOP vs OOP
OOP 방식은 객체마다 로직과 부가 기능(로깅, 트랜잭션)등의 코드를 작성합니다.
이는 유지보수를 위한 부가기능은 동일한 기능을 수행할 확률이 높아, 핵심 기능을 구현할 때 마다 동일한 코드가 포함될 가능성이 높습니다.
AOP 관점에서는 부가 기능을 하나의 공통 로직으로 처리하도록 모듈화해 로직이 수행되기 전 또는 후 등 원하는 곳에 삽입하도록 할 수 있습니다.
스프링 프레임워크 vs 스프링 부트
스프링 부트는 스프링이 제공하는 프로젝트 중 하나입니다.
스프링에서는 개발의 엔터프라이즈급 애플리케이션을 개발하기 위한 다양한 기능과 모듈을 제공합니다.
다만 스프링은 설정이 XML 파일이나 Java Config와 같이 상당한 수동 설정이 필요한 경향이 있습니다.
xml 파일 설정 예시
- 사용하려는 service
package com.zerobase.convpay.service;
import com.zerobase.convpay.dto.*;
import com.zerobase.convpay.type.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class ConveniencePayService { //편결이
private final Map<PayMethodType,PaymentInterface> paymentInterfaceMap = new HashMap<>();
private final DiscountInterface discountInterface;
public ConveniencePayService(Set<PaymentInterface> paymentInterfaceSet, DiscountInterface discountInterface) {
paymentInterfaceSet.forEach(
paymentInterface -> paymentInterfaceMap.put(
paymentInterface.getPayMethodType(),
paymentInterface
)
);
this.discountInterface = discountInterface;
}
public PayResponse pay(PayRequest payRequest){
PaymentInterface paymentInterface = paymentInterfaceMap.get(payRequest.getPayMethodType());
Integer discountedAmount = discountInterface.getDiscountedAmount(payRequest);
PaymentResult payment = paymentInterface.payment(payRequest.getPayAmount());
// Exception case
if(payment == PaymentResult.PAYMENT_FAIL){
return new PayResponse(PayResult.FAIL, 100);
}
// Success Case
return new PayResponse(PayResult.SUCCESS,100);
}
}
- spring-config.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="conveniencePayService" class="com.zerobase.convpay.service.ConveniencePayService">
<constructor-arg name="paymentInterfaceSet">
<set>
<ref bean="moneyAdapter"/>
<ref bean="cardAdapter"/>
</set>
</constructor-arg>
<constructor-arg name="discountInterface" ref="discountByPayMethod"/>
</bean>
<bean id="cardAdapter" class="com.zerobase.convpay.service.CardAdapter"/>
<bean id="moneyAdapter" class="com.zerobase.convpay.service.MoneyAdapter"/>
<bean id="discountByConvenience" class="com.zerobase.convpay.service.DiscountByConvenience"/>
<bean id="discountByPayMethod" class="com.zerobase.convpay.service.DiscountByPayMethod"/>
</beans>
- 설정파일을 이용
public static void main(String[] args) {
// 사용자
// 우리가 만든 설정파일을 토대로 사용하게끔 만든다.
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
ConveniencePayService conveniencePayService = applicationContext.getBean("conveniencePayService", ConveniencePayService.class);
// 결제 1000원
PayRequest payRequest = new PayRequest(ConvenienceType.G25, 50, PayMethodType.CARD);
PayResponse payResponse = conveniencePayService.pay(payRequest);
System.out.println(payResponse);
// GS25, 취소 500원
PayCancelRequest payCancelRequest = new PayCancelRequest(ConvenienceType.G25, 500, PayMethodType.MONEY);
PayCancelResponse payCancelResponse = conveniencePayService.payCancel(payCancelRequest);
System.out.println(payCancelResponse);
}
이와같이 스프링 프레임워크는 개발에 필요한 각 모듈의 의존성을 직접 설정해야 했습니다.
또 다른 라이브러리를 사용한다면 스프링에 호환되는 버전을 명시해야 정상 동작이 하는데, 이런 외부 라이브러리도 버전을 올리는 상황에서는 연관된 다른 라이브러리의 버전까지도 고려해야 합니다.
이런 설정 복잡성을 해결하기 위해 나온 것이 스프링 부트입니다.
Spring boot
스프링 부트에서는 'spring-boot-starter' 라는 의존성을 제공합니다.
'spring-boot-starter'에는 여러 종류가 있습니다.
각 라이브러리의 기능과 관련해서 자주 사용되고 서로 호환되는 버전의 모듈 조합을 제공합니다.
자동 설정: SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
@SpringBootApplication은 스프링 부트에서 주로 사용되는 어노테이션 중 하나로, 애플리케이션의 기본 설정을 지정하는 데 사용됩니다. 이 어노테이션은 다음 세 가지 어노테이션의 조합체로 이루어져 있습니다.
1. @Configuration
해당 클래스가 스프링의 Java 기반 구성 클래스임을 나타냅니다.
스프링 컨텍스트에 빈을 정의하는 Java 설정 클래스로 사용됩니다.
2. @EnableAutoConfiguration
자동 구성 기능을 활성화합니다.
클래스패스 상의 다양한 설정을 기반으로 애플리케이션 컨텍스트를 구성합니다. 예를 들어, 데이터베이스 연결, 웹 서버 등의 기본적인 설정들을 자동으로 수행합니다.
아래 파일은 @EnablceAutoConfiguration를 통해 spring-boot-autoconfigure패키지에 추가된 spring.factories 파일입니다.
# ApplicationContext Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.autoconfigure.integration.IntegrationPropertiesEnvironmentPostProcessor
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.MissingR2dbcPoolDependencyFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.MultipleConnectionPoolConfigurationsFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer
# Template Availability Providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider
# DataSource Initializer Detectors
org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDatabaseInitializerDetector
# Depends on Database Initialization Detectors
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\
org.springframework.boot.autoconfigure.batch.JobRepositoryDependsOnDatabaseInitializationDetector,\
org.springframework.boot.autoconfigure.quartz.SchedulerDependsOnDatabaseInitializationDetector,\
org.springframework.boot.autoconfigure.session.JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector
이 파일은 각 라이브러리가 제공하는 자동 구성 클래스들을 정의하고 있습니다.
@EnableAutoConfiguration는 spring.factories 파일을 참조하여 자동 구성 클래스들을 확인하고 활성화합니다.
3. @ComponentScan
스프링이 해당 클래스의 패키지와 그 하위 패키지를 스캔하여 스프링 빈으로 등록할 컴포넌트를 찾도록 지시합니다.
기본적으로 @SpringBootApplication이 위치한 패키지를 기준으로 스캔합니다.
@SpringBootApplication 어노테이션을 사용하면 위의 세 가지 어노테이션을 한 번에 적용할 수 있어, 애플리케이션의 주진입점을 설정하고 기본적인 스프링 부트 구성을 쉽게 수행할 수 있습니다. 이는 스프링 부트 애플리케이션을 더 간결하게 작성할 수 있도록 도와주는 중요한 어노테이션입니다.
'spring > spring' 카테고리의 다른 글
[스프링 부트 핵심 가이드] HTTP 요청 메서드 받기 (0) | 2024.02.01 |
---|---|
[스프링 부트 핵심 가이드] pom.xml (0) | 2024.02.01 |
[Spring] @Transactional (0) | 2024.02.01 |
[Spring] 프로젝트 구조 알아보기 (0) | 2024.01.30 |
[스프링 부트 핵심 가이드] MSA, 스프링 부트 동작방식,레이어드 아키텍처 (0) | 2024.01.25 |