Java 2022. 11. 7. 02:08

백기선 스프링 프레임워크 핵심 기술 완강 후기

후기
  • Spring Framework의 Core 부분만 간략하게 학습한 것인데도 상당히 방대하다고 느꼈다.
  • Spring Boot를 사용하면 상당히 편리해 보이는 부분이 많아서, 요즘 추세에 따라 반드시 알아야 할 것 같다.
  • 토비의 스프링 3에 많은 정보가 있는 듯 하다. 백기선 스프링 커리큘럼 완강 이후 심화 학습용으로 보면 좋을 것 같다.
  • 리액트나 안드로이드의 라이프사이클을 파악해야 쉽게 프로그래밍할 수 있는 것처럼, 스프링 Bean의 라이프사이클을 아는 것이 중요한 것 같다.

 

스프링
  • 등장 시기 : 2003년
  • 스프링 5부터는 서블릿 기반이 아닌 서버 애플리케이션도 개발할 수 있게 되었다. (WebFlux 지원)
디자인 철학
  • 특정 기술을 강요하지 않는다.
  • 다양한 관점을 지향한다.
  • 하위 호환성을 지킨다.
  • API를 신중하게 설계한다.
  • 높은 수준의 코드를 지향한다.

 

스프링 프레임워크 핵심 기술
  • Spring IoC Container
    • IoC Container
      • 객체가 사용하는 의존 객체를 직접 만들어 사용하는 게 아니라, 주입 받아 사용하는 방법을 뜻한다.
      • DI(Dependency Injection, 의존성 주입)이라고도 한다.
    • Spring Bean
      • 스프링 IoC 컨테이너가 관리하는 객체이다.
      • 사용 시 장점
        • 의존성 관리가 수월하다.
        • 스코프를 쉽게 지정할 수 있다.
          • 싱글톤, 프로토타입, 쓰레드 등
        • 라이프사이클 인터페이스가 존재하여, 필요 시 해당 메서드를 Override하여 사용할 수 있다.
      • 참고) Java Bean
        • 스프링 빈이 아닌 자바 빈 규약도 존재한다.
        • 자바 빈 특징
          • 기본 패키지 외 특정 패키지에 속한다.
          • 매개변수가 없는 기본 생성자가 존재한다.
          • 멤버변수의 접근제어자는 private이다.
          • 접근제어자가 public인 getter, setter가 존재한다.
          • (Optional) 직렬화가 가능하다.
    • 스프링 빈 설정 방법
      • 스프링 빈 직접 설정 (스프링 빈에 대한 정의)
        • 이름, 클래스, 스코프, Constructor, Setter 등
      • Component Scan
        • 특정 패키지 이하의 모든 클래스를 순회하여 @Component 애노테이션이 붙은 클래스를 스프링 빈으로 등록한다.
        • 설정 방법
          • context:component-scan : XML
          • @ComponentScan : Java
    • @Autowired
      • 의존 객체의 타입을 통해 해당 스프링 빈을 찾아서 주입하는 애노테이션이다.
      • 옵션
        • required (기본 값 = true) : 스프링 빈에서 해당 타입을 못 찾으면 애플리케이션 구동에 실패한다.
      • 사용할 수 있는 위치
        • 생성자 주입 (스프링 4.3 부터 생략 가능)
        • 수정자(Setter) 주입
        • 필드 주입
      • 같은 타입의 빈이 여러 개 인 경우 (상속, 인터페이스 구현 등)
        • 기본적으로는 변수명을 PascalCase로 변환한 타입의 스프링 빈을 주입한다.
        • 우선적으로 주입하고 싶은 스프링 빈에 @Primary 애노테이션을 붙이면 우선적용된다. (권장)
        • @Qualifier(빈이름) 애노테이션을 통해서 개별적으로 적용할 수도 있다.
    • @Component, @ComponentScan
      • @Component : 스캔 대상이 될 빈을 지정한다.
        • @Component 애노테이션을 적용한 애노테이션들
          • @Repository
          • @Service
          • @Controller
          • @Configuration

           

      • @ComponentScan : 스캔할 패키지 위치와 필터링 할 애노테이션에 대한 정보를 제공한다.
      • 스프링 빈을 직접 등록하는 방법
        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로 감싸서 프록시 패턴을 적용할 수도 있다. (비권장 - 소스코드에 스프링코드가 들어가기 때문)
    • 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 : 비동기로 실행한다. (기본 핸들링은 동기적으로 처리된다.)
      • 스프링 제공 기본 이벤트
        • 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 타입에 따라 결정된다.
          • ClassPathXmlApplicationContextClassPathResource
          • FileSystemXmlApplicationContextFileSystemResource
          • WebApplicationContextServletContextResource
        • ApplicationContext 타입에 상관없이 리소스 타입을 강제하기 위해서 java.net.URL 접두어 중 하나를 사용할 수 있다. (권장)
          • classpath:ClassPathResource
          • file://FileSystemResource
            • 루트 경로부터 시작하려면 다소 이상하게 보이지만 file:///something/path 이런 식으로 작성해야 한다.
    • Validation 추상화
      • 모든 계층(웹, 서비스, 데이터)에서 사용해도 된다. (어떠한 계층과도 관계가 없다.)
      • 데이터 바인딩 시 같이 사용되기도 한다.
      • 메서드 오버라이딩
        • supports(Class clazz) : 특정 타입의 객체를 검증할 때 사용할 것인지 결정한다.
        • validate(Object obj, Errors e) : 실제 검증 로직을 이 안에서 구현한다.
          • 구현 시 ValidationUtils 를 사용한다.
      • 스프링 부트 2.0.5 이상 버전 사용 시
        • LocalValidatorFactoryBean 을 스프링 빈으로 자동 등록해준다.
        • Default message도 위의 클래스에서 제공한다.

       

    • 데이터 바인딩 추상화
      • 사용자 입력 값(문자열)을 애플리케이션 도메인 모델(객체)에 동적으로 변환하여 입력하는 기능이다.
      • PropertyEditor : 스프링 3.0 이전까지 DataBinder 가 바인딩 작업에 사용하던 인터페이스이다.
        • 상태 정보를 저장하기 때문에 thread-safe하지 않다.
        • Object ~ String 간 변환만 지원하여, 사용 범위가 다소 제한적이다.
        • PropertyEditorSupportgetAsText(), setAsText 메서드를 오버라이딩하여 사용한다.
      • ConversionService : DataBinder 대신에 타입 변환 작업에 사용하는 인터페이스이며, thread-safe 하다.
        • addFormatters() 메서드를 통해 ConverterFormatter를 등록할 수 있다.
          • DefaultFormattingConversionServiceFormatterRegistryConverterRegistry 상속 구조
        • 스프링 MVC, SpEL 등에서 사용한다.
        • Converter : 일반적인 S(source) → T(target) 타입 변환기
          • 상태 정보를 저장하지 않아 thread-safe하다.
          • ConverterRegistry 에 등록해서 사용한다.
        • Formatter : PropertyEditor 를 대체한다.
          • Object ~ String 변환에 사용한다.
          • 문자열을 Locale에 따라 다국화 할 수 있다.
          • FormatterRegistry 에 등록해서 사용한다.
        • 스프링 부트에서 웹 애플리케이션인 경우, public classWebConversionService extendsDefaultFormattingConversionService 를 스프링 빈으로 등록하여, FormatterConverter 스프링 빈을 찾아 자동으로 등록해준다.

       

  • 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