Java
2022. 11. 7. 02:08
백기선 스프링 프레임워크 핵심 기술 완강 후기
후기
- Spring Framework의 Core 부분만 간략하게 학습한 것인데도 상당히 방대하다고 느꼈다.
- Spring Boot를 사용하면 상당히 편리해 보이는 부분이 많아서, 요즘 추세에 따라 반드시 알아야 할 것 같다.
- 토비의 스프링 3에 많은 정보가 있는 듯 하다. 백기선 스프링 커리큘럼 완강 이후 심화 학습용으로 보면 좋을 것 같다.
- 리액트나 안드로이드의 라이프사이클을 파악해야 쉽게 프로그래밍할 수 있는 것처럼, 스프링 Bean의 라이프사이클을 아는 것이 중요한 것 같다.
스프링
- 등장 시기 : 2003년
- 스프링 5부터는 서블릿 기반이 아닌 서버 애플리케이션도 개발할 수 있게 되었다. (WebFlux 지원)
- 아래 내용은 Spring Framework Core 에 대한 내용이다. (https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core)
디자인 철학
- 특정 기술을 강요하지 않는다.
- 다양한 관점을 지향한다.
- 하위 호환성을 지킨다.
- API를 신중하게 설계한다.
- 높은 수준의 코드를 지향한다.
스프링 프레임워크 핵심 기술
Spring IoC Container
IoC Container
- 객체가 사용하는 의존 객체를 직접 만들어 사용하는 게 아니라, 주입 받아 사용하는 방법을 뜻한다.
- DI(Dependency Injection, 의존성 주입)이라고도 한다.
Spring IoC Container
- Spring Bean을 구성하고 제공한다.
Spring Bean
- 스프링 IoC 컨테이너가 관리하는 객체이다.
사용 시 장점
- 의존성 관리가 수월하다.
- 스코프를 쉽게 지정할 수 있다.
- 싱글톤, 프로토타입, 쓰레드 등
- 라이프사이클 인터페이스가 존재하여, 필요 시 해당 메서드를 Override하여 사용할 수 있다.
참고) Java Bean
- 스프링 빈이 아닌 자바 빈 규약도 존재한다.
자바 빈 특징
- 기본 패키지 외 특정 패키지에 속한다.
- 매개변수가 없는 기본 생성자가 존재한다.
- 멤버변수의 접근제어자는 private이다.
- 접근제어자가 public인 getter, setter가 존재한다.
- (Optional) 직렬화가 가능하다.
ApplicationContext
다음 인터페이스들을 상속받는 인터페이스이다.
MessageSource
: i18n (다국어 처리) 대응
스프링에서 주로 사용하는 두 가지는 다음과 같다.
스프링 빈 설정 방법
스프링 빈 직접 설정 (스프링 빈에 대한 정의)
- 이름, 클래스, 스코프, Constructor, Setter 등
Component Scan
- 특정 패키지 이하의 모든 클래스를 순회하여
@Component
애노테이션이 붙은 클래스를 스프링 빈으로 등록한다.
설정 방법
context:component-scan
: XML
@ComponentScan
: Java
- 특정 패키지 이하의 모든 클래스를 순회하여
@Autowired
- 의존 객체의 타입을 통해 해당 스프링 빈을 찾아서 주입하는 애노테이션이다.
- 옵션
required
(기본 값 = true) : 스프링 빈에서 해당 타입을 못 찾으면 애플리케이션 구동에 실패한다.
사용할 수 있는 위치
- 생성자 주입 (스프링 4.3 부터 생략 가능)
- 수정자(Setter) 주입
- 필드 주입
같은 타입의 빈이 여러 개 인 경우 (상속, 인터페이스 구현 등)
- 기본적으로는 변수명을 PascalCase로 변환한 타입의 스프링 빈을 주입한다.
- 우선적으로 주입하고 싶은 스프링 빈에
@Primary
애노테이션을 붙이면 우선적용된다. (권장)
@Qualifier(빈이름)
애노테이션을 통해서 개별적으로 적용할 수도 있다.
동작 원리
AutowiredAnnotationBeanPostProcessor extends BeanPostProcessor
라이프사이클 인터페이스를 통해@Autowired
,@Value
,@Inject
애노테이션을 처리한다.
@Component, @ComponentScan
@Component
: 스캔 대상이 될 빈을 지정한다.@Component
애노테이션을 적용한 애노테이션들@Repository
@Service
@Controller
@Configuration
@ComponentScan
: 스캔할 패키지 위치와 필터링 할 애노테이션에 대한 정보를 제공한다.- 실제 스캐닝은
ConfigurationClassPostProcessor
에 의해 처리된다.
- 실제 스캐닝은
- 스프링 빈을 직접 등록하는 방법
public static void main(String[] args) { new SpringApplicationBuilder() .sources(Demospring51Application.class) .initializers((ApplicationContextInitializer<GenericApplicationContext>) applicationContext -> { applicationContext.registerBean(MyBean.class); }) .run(args); }
빈 스코프
스코프 종류
- 싱글톤
프로토타입
- Request
- Session
- WebSocket
- 기타 등등
싱글톤 빈이 프로토타입 빈을 참조할 경우
- 프로토타입 빈은 사용할 때마다 다른 인스턴스를 사용해야 하는데, 싱글톤 빈은 반드시 하나만 존재하므로 꺼내 사용할 때 프로토타입 빈이 수정되지 않는 문제가 발생한다.
이를 해결하기 위해 Proxy 패턴을 사용한다.
- ScopedProxy : 프로토타입 빈 클래스
@Scope
애노테이션에proxyMode=ScopedProxyMode.TARGET_CLASS
속성을 주면 CGLib 다이나믹 프록시가 적용되어 매번 인스턴스가 달라진다.TARGET_CLASS
로 주는 이유 : JDK 다이나믹 프록시는 Interface로만 만들 수 있는데, Class를 대상으로 하여 서드파티 다이나믹 프록시 라이브러리인 CGLib를 사용하도록 지정함
- ObjectProvider : 프로토타입 빈을 참조하는 코드를
ObjectProvider
로 감싸서 프록시 패턴을 적용할 수도 있다. (비권장 - 소스코드에 스프링코드가 들어가기 때문)
- ScopedProxy : 프로토타입 빈 클래스
Environment
ApplicationContext extends EnvironmentCapable
:EnvironmentCapable
인터페이스 기반으로 환경 설정을 제공한다.
프로파일
- 개발 환경과 배포 환경에서 서로 다른 빈을 사용하고 싶을 때 적용하는 프로파일을 의미한다.ex. 배포 시에만 사용할 모니터링 빈은 테스트 환경에서 필요 없으므로 등록하지 않고싶은 경우
프로파일 정의 방법 :
@Profile("프로파일명")
애노테이션을 클래스나 메소드에 붙인다.- 프로파일 표현식 : !, &, | 등 논리 연산자를 조합하여 다양하게 활동할 수 있다.
- 프로파일 설정 방법 : Java VM 옵션으로 다음 값을 준다.
-Dspring.profiles.active="프로파일명"
- 혹은 IntelliJ 설정에서 Active Profile 속성으로 값을 주면 되는데 아마 Ultimate 버전만 뜨는 듯 하다.
프로퍼티
- VM 옵션이나 프로퍼티 파일에서 속성을 불러와 사용할 수 있다.
@PropertySource
: 프로퍼티 파일에서 속성을 불러올 수 있다.
- 우선 순위가 높은 프로퍼티를 적용하여 제공한다.
- 스프링 부트 기본 프로퍼티 소스 :
application.properties
MessageSource
ApplicationContext extends MessageSource
: 국제화 기능(다국어 지원, i18n)을 제공하는 인터페이스이다.
- 스프링 부트 사용 시 기본적으로
message.properties
등 파일을 사용할 수 있다.- 다국어 메시지 프로퍼티 파일 네이밍 규칙은 해당 언어를 언더바로 이으면 된다.
messages_ko_kr.properties
- 다국어 메시지 프로퍼티 파일 네이밍 규칙은 해당 언어를 언더바로 이으면 된다.
ReloadableResourceBundleMessageSource
객체를 통해 프로퍼티 파일이 실시간으로 반영되도록 할 수 있다. (Build 시 적용된다.)
ApplicationEventPublisher
ApplicationContext extends ApplicationEventPublisher
: 이벤트 프로그래밍에 필요한 인터페이스를 제공한다. (옵저버 패턴)
- Event
ApplicationEvent
를 상속받는 클래스를 사용한다. (스프링 4.2부터는 상속 안 해도 사용 가능)
- 이벤트 발생시키기 :
ApplicationEventPublisher.publishEvent();
이벤트 핸들링 :
ApplicationListener<이벤트>
를 구현하여 빈으로 등록한다.- 스프링 4.2부터는
@EventListener
애노테이션을 스프링 빈 메소드에 붙여서 사용할 수 있다.
@Order
: 동일 이벤트에 대한 핸들링의 순서를 정할 수 있다.
@Async
: 비동기로 실행한다. (기본 핸들링은 동기적으로 처리된다.)
- 스프링 4.2부터는
스프링 제공 기본 이벤트
ContextRefreshedEvent
:ApplicationContext
초기화 or 리프레시 시 발생한다.
ContextStartedEvent
:ApplicationContext
start() 를 통해 라이프사이클 빈이 시작 신호를 받은 시점에 발생한다.
ContextStoppedEvent
:ApplicationContext
stop() 을 통해 라이프사이클 빈이 정지 신호를 받은 시점에 발생한다.
ContextClosedEvent
:ApplicationContext
close()를 통해 싱글톤 빈이 소멸되는 시점에 발생한다.
RequestHandledEvent
: HTTP 요청을 처리했을 때 발생한다.
ResourceLoader
ApplicationContext extends ResourceLoader
: 리소스를 읽어오는 기능을 제공한다.
- 리소스 읽어오는 메서드 :
getResource(String location)
리소스를 어떤 방식으로 읽어올 수 있는가? (
location
종류)- 파일 시스템
- classpath
- URL
- 상대경로, 절대경로
스프링 추상화
Resource 추상화
org.springframework.core.io.Resource
: 스프링 내부에서 많이 사용하는,java.net.URL
을 추상화 한 인터페이스이다.
추상화 이유
- classpath 기준 리소스 읽어오는 기능 부재
ServletContext
기준 상대 경로로 읽어오는 기능 부재
주요 메서드
getInputStream()
exists()
isOpen()
getDescription()
: 전체 경로 포함한 파일 이름 또는 실제 URL
주요 구현체
UrlResource
: http, https, ftp, file, jar 프로토콜 기본 지원
ClassPathResource
:classpath:
접두어 지원
FileSystemResource
ServletContextResource
: 웹 애플리케이션 루트에서 상대 경로로 리소스를 찾는다.
리소스 읽어오기
리소스의 타입은
getResource(String location)
의location
문자열과ApplicationContext
타입에 따라 결정된다.ClassPathXmlApplicationContext
→ClassPathResource
FileSystemXmlApplicationContext
→FileSystemResource
WebApplicationContext
→ServletContextResource
ApplicationContext
타입에 상관없이 리소스 타입을 강제하기 위해서java.net.URL
접두어 중 하나를 사용할 수 있다. (권장)classpath:
→ClassPathResource
file://
→FileSystemResource
- 루트 경로부터 시작하려면 다소 이상하게 보이지만
file:///something/path
이런 식으로 작성해야 한다.
- 루트 경로부터 시작하려면 다소 이상하게 보이지만
Validation 추상화
- JSR-303(Bean Validation 1.0)과 JSR-349(Bean Validation 1.1)을 지원한다. (LocalValidatorFactoryBean)
- 모든 계층(웹, 서비스, 데이터)에서 사용해도 된다. (어떠한 계층과도 관계가 없다.)
- 데이터 바인딩 시 같이 사용되기도 한다.
메서드 오버라이딩
supports(Class clazz)
: 특정 타입의 객체를 검증할 때 사용할 것인지 결정한다.
validate(Object obj, Errors e)
: 실제 검증 로직을 이 안에서 구현한다.- 구현 시
ValidationUtils
를 사용한다.
- 구현 시
스프링 부트 2.0.5 이상 버전 사용 시
LocalValidatorFactoryBean
을 스프링 빈으로 자동 등록해준다.
- Default message도 위의 클래스에서 제공한다.
데이터 바인딩 추상화
- 사용자 입력 값(문자열)을 애플리케이션 도메인 모델(객체)에 동적으로 변환하여 입력하는 기능이다.
PropertyEditor
: 스프링 3.0 이전까지DataBinder
가 바인딩 작업에 사용하던 인터페이스이다.- 상태 정보를 저장하기 때문에 thread-safe하지 않다.
- Object ~ String 간 변환만 지원하여, 사용 범위가 다소 제한적이다.
PropertyEditorSupport
의getAsText()
,setAsText
메서드를 오버라이딩하여 사용한다.
ConversionService
:DataBinder
대신에 타입 변환 작업에 사용하는 인터페이스이며, thread-safe 하다.addFormatters()
메서드를 통해Converter
와Formatter
를 등록할 수 있다.DefaultFormattingConversionService
→FormatterRegistry
→ConverterRegistry
상속 구조
- 스프링 MVC, SpEL 등에서 사용한다.
Converter
: 일반적인 S(source) → T(target) 타입 변환기- 상태 정보를 저장하지 않아 thread-safe하다.
ConverterRegistry
에 등록해서 사용한다.
Formatter
:PropertyEditor
를 대체한다.- Object ~ String 변환에 사용한다.
- 문자열을 Locale에 따라 다국화 할 수 있다.
FormatterRegistry
에 등록해서 사용한다.
- 스프링 부트에서 웹 애플리케이션인 경우,
public classWebConversionService extendsDefaultFormattingConversionService
를 스프링 빈으로 등록하여,Formatter
와Converter
스프링 빈을 찾아 자동으로 등록해준다.
SpEL (Spring Expression Language)
- Unified EL 과 비슷하나, 메소드 호출을 지원하며, 문자열 템플릿 기능도 제공한다.
- 스프링 3.0 부터 지원하는 표현식이다.
문법
#{”표현식”}
${"프로퍼티"}
- 표현식 안에 프로퍼티 사용 가능 (
#{${my.data} + 1}
)
주로 사용하는 곳
@Value
,@ConditionalOnExpression
애노테이션
- 스프링 시큐리티
- 스프링 데이터 :
@Query
애노테이션
- Thymeleaf
스프링 AOP (Aspect-Oriented Programming)
AOP : 흩어진 Aspect를 모듈화 하는 프로그래밍 기법이다.
- Aspect : 관심사를 모듈화 한 것. 즉 공통적으로 사용되는 코드 모듈을 의미한다.
- Advice : Aspect에서 수행할 실질적 작업
- Target : Aspect의 적용 대상
- Join Point : Advice가 적용될 수 있는 지점
- Pointcut : Advice가 적용될 Join Point 지점을 의미한다. (Join Point의 한 부분)
Java AOP 구현체
- AspectJ
- Spring AOP
스프링 AOP 특징
프록시 기반의 AOP 구현체이다.
- 프록시 패턴 사용 이유 : 기존 코드의 변경 없이 접근 제어 또는 부가 기능을 추가하기 용이하다.
- 스프링 빈에만 AOP 적용 가능하다.
동적 프록시
- Java 제공 프록시 : 인터페이스 기반의 프록시를 생성할 수 있다.
- CGlib : 클래스 기반의 프록시 생성도 지원한다.
스프링 IoC :
AbstractAutoProxyCreator implements BeanPostProcessor
를 통해 기존 스프링 빈을 대체하는 동적 프록시 빈을 생성하여 등록시킨다.
- 프록시 클래스를 작성하여 구현할 수 있으나, 애노테이션 기반의 스프링 AOP를 통해 매번 프록시 클래스를 작성해야 하는 번거로움을 줄일 수 있다.
@AOP
- 스프링 부트에서 제공하는 AOP 애노테이션이다.
Aspect 정의 :
@Aspect
- 빈으로 등록해야 하므로
@Component
도 추가해야 한다.
- 빈으로 등록해야 하므로
Advice 정의
다음 애노테이션을 통해 Advice가 적용될 범위를 설정할 수 있다.
@Around
:ProceedingJoinPoint
매개변수를 받는 함수를 통해 Advice를 구현한다. 원래의 메서드가 실행되기 전후로 Advice를 설정할 수 있는 장점이 있다.
@Before
@AfterReturning
@AfterThrowing
Pointcut 정의 :
@Pointcut
Pointcut Designator (표현식)
execution
@annotation
bean
포인트컷 조합식
&&
,||
,!
Null-safety
- 스프링 프레임워크 5에 추가된, 컴파일 시점에 최대한 NullPointerException을 방지하기 위한 Null 관련 애노테이션이다.
종류
@NonNull
@Nullable
@NonNullApi
: 패키지 레벨
@NonNullFields
: 패키지 레벨
TODO
'Java' 카테고리의 다른 글
JIT 컴파일 (0) | 2023.01.14 |
---|---|
OpenJDK 아카이브 링크 (0) | 2022.12.10 |
Java의 정석 13장 리뷰 (1) | 2022.11.11 |
Java 이클립스 The project description file (.project) for ~ is missing 에러 (0) | 2021.12.13 |