2022/04/28 Spring과 Spring Core기술들에 대한 간략한 요약

김석진·2022년 4월 30일
0

다시 초심으로

목록 보기
5/19

🌱자바,스프링, 스프링부트🌱

JAVA: 객체지향적 프로그래밍언어

public class JavaProject {
	// Java를 처음 접하면서 보게되는 코드
	public static void main(String[] args) {
		System.out.println("Hello World");
  }
}

스프링의 근간이 되는 언어이다 스프링이 책이라고 하면 자바는 한글이다
스프링자체도 거의 대부분 자바로 만들어져 있고, 스프링은 자바뿐만아니라 코틀린,그루비로도 사용할 수 있다.

요즘은 자바에서 코틀린으로 넘어가는 추세인거 같기도하기때문에 코틀린에대해서도 공부를 해야겠다!

스프링개발에 들어간 언어들

Spring Framework:기업용 어플리케이션을 만드는데 사용가능한 오픈소스 프레임워크

자바를 이용해서 어플리케이션을 쓰기위해 활용하는 프레임워크다(여러툴이있는 템플릿)

스프링은 갑자기 툭튀어나온게 아니다. 웹이 활성화되면서 상호간의 응답이 필요한 어플리케이션이 필요해졌고 서블릿이 나오기 시작했고 서블릿을 만들기위한 스펙이 J2EE라는 프레임워크나 스펙들이 나오기 시작했다(EJB). 다루기가 많이 어려웠다고 한다. 그렇게 때문에 스프링이라는것을 만들게 되었다.

자바, 서블릿, J2EE >>>>> 스프링 프레임워크

스프링은 라이브러리와 다르게 프레임워크이다. 프레임워크는 큰영역의 틀이라고 생각하면된다.

스프링프레임워크에는 이렇게 많은 기능들을 담고있는데 그 중에서 적합한 툴을 선택하여 사용것이 좋다.

Spring boot: 스프링 기반으로 자주사용되는 설정을 손쉽게 개발할 수 있도록 해주는 상위 프레임워크이다.

스프링보다 한층 더 편리한 프레임워크라고 생각한다 내가 사용을 해보면서 dependency를 추가하거나 자바 버젼 세팅등등 start.spring.io에서 세팅을 해서 바로 띄울수있는 있다. 자동설정, 설정 표준화가 되어있어 손쉽게 접근할 수있고 원한다면 모두 마음대로 설정을 할 수있다는 장점이 있었다.


웹 어플리케이션 서버가 내장되어있고 기본적으로 톰켓이 내장되어있어서 따로 세팅을 해줄 필요가없는 장점이있었다.

스프링 프레임워크 핵심기술 넓게 알아보기

스프링 프레임워크를 사용하면서 따라하기만 하면 누구나 만들수있다 하지만 프로젝트나 결과물을 만들면서 따라하기만 하면 이게 왜 이렇게 동작하는지 이해를 못할때가 있다고 생각한다.. 물론 나도 그렇고 그래서 스프링 프레임워크의 기술들 종류들을 알아보고 왜 이렇게 동작하는지에 대해서 알아볼려고한다
스프링을 공부하면서 매우 많이 나오는 핵심기술들이다.

Core(DI,IoC)

내가 만든 클래스를 스프링이 직접 관리하여 애플리케이션을 동작하게 한다.

AOP(Aspect Oriented Programming)

공통적인 코드를 프레임워크 레벨에서 지원해주는 방법

Validation,Data binding

검증, 외부에서 받은 데이터를 객체로 담아내는 방법

Resource

스프링 내부에서 설정이 들어있는 파일들에 접근하는 동작원리

SpEL(Spring Expression Language)

설정값들을 외부에서 주입을 받을 때 활용
짧은 표현식을 통해 필요한 데이터나 설정 값을 얻어올 수 있게 하는 특별한 형태의 표현식에 가까운 간편한 언어

스프링의 디자인철학

스프링이라는 건 다양한 기능들을 계속 발전시켜가면서 제공하고 있기때문에 모든 기능에 대해서 다양한 가능성(다양한모듈)을 사용가능하다. 심지어 외부 모듈을 활용가능하다.
-> 이런 높은 자유도가 스프링을 어렵게 하는 요소이다.

이전 버전과의 강력한 호환성,API 디자인을 섬세하게 노력하기때문에 스프링 코드 자체가 하나의 좋은 참고 소스이므로 시간이 날때마다 스프링 내부 코드들을 까고 분석 해볼예정이다.

DI-Dependency Injection, IoC-Inversion of Control

IoC나 DI는 레고 같은것이라고 강사 님이 말씀해주셨다 스프링은 바닥판에 깔려있고 우리는 그 위에 나의 어플리케이션을 만들어서 붙이면 된다라고 생각하면 된다고하셨다.
나도 처음에 Spring을 접했을 때는 IoC? DI가 뭐지? 에이 그냥 외워야지 했는데 막상 다시 공부를 하면서 천천히 읽어보니 Spring이 Class들을 관리를 하고 내가 관리할 필요가 없는 방법이구나 라고 느끼게되었다.
DI랑 IoC를 배울때 Bean이라는 용어가 나오는데 이에 대해서 알아보겠다!

Bean이란?

Java에서 javaBean

행위들은 없고 데이터를 저장하기위한구조체로 자바 빈 규약이라는 것을 따르는 구조체
private 프로퍼티와 getter/setter로만 데이터를 접근한다.
인수(argument)가 없는 기본 생성자가 있음!

public class JavaBean {
	private String id;
	private Integer count;

	public JavaBean(){}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public Integer getCount() {
		return count;
	}

	public void setCount(Integer count) {
		this.count = count;
	}
}

스프링에서의 Bean 자바Bean과는 다름


우리가 만든 A,B,C라는 클래스를 빈으로 등록을 하면 Spring에 있는 IoC컨테이너에 담겨진다.

  • 스프링 IoC 컨테이너에 의해 생성되고 관리되는 객체가 Java Bean이다.
  • 자바에서처럼 new Object();로 생성하지 않으며 각각의 Bean들끼리는 서로 편리하게 의존할 수 있다.
    Spring Application Context에 Bean의 리스트가 있다.
    요약하자면 스프링에서의 Bean은 우리가 만든 클래스를 IoC Container 안에 실체로 들고있는 클래스 인스턴스들인데 인스턴스들의 Application context가 설정값에 따라서 설정값을 입혀주면서 공통된 처리를 할수있게 입혀진 클래스들을 Bean이라고 할 수 있다.

스프링 컨테이너 개요


ApplicationContext 인터페이스를 통해 제공되는 스프링 컨테이너는 Bean객체의 생성 및 Bean들의 조립(상호의존성 관리)를 담당함

Bean 등록

과거에는 xml로 설정을 따로 관리하여 등록했다-> 나도 예전 강의를 보면서 xml에 빈등록하는 것을 본적이 있다 매우 불편하다고 느꼈는데
현재에는 annotation기반으로 Bean을 등록하며 예를 들면 @Bean, @Controller, @Service등이 있다.

@Controller, @Service도 빈으로 등록됨

Bean 등록시 정보

  • Class 경로
  • Bean의 이름
    - 기본적으로 첫 문자만 소문자로 변경
    • 원하는 경우 변경가능
  • Scope는 Bean을 생성하는 규칙
    빈도 다른 자바 클래스 처럼 프로퍼티를 들고있는 클래스임
    - singleton(default):컨테이너에 단일로 생성 , 처음 생성 후 서버가 내려가기전까지 유지됨
    - prototype: 작업 시마다 Bean을 새로 생성하고 싶을경우(Spring Batch에서 사용될때 있음)
    - request: http요청마다 새롭게 Bean을 생성하고 싶을경우

Bean LifeCycle callback

빈은 default가 싱글톤이기 때문에 애플리케이션이 실행될때 생성이된다.
빈이 생성/변경/파괴할때 특정 작업을 해줘야한다. 이때 Bean LifeCycle callback을 이용한다
callback은 어떤이벤트발생시 호출되는 메소드 이다.
lifeCycle callback은 Bean을 생성하고 초기화하고 파괴하는 등 특정 시점에 호출되도록 정의된 함수이다.

  • 주로 많이 사용되는 콜백
    - @PostConstruct:빈 생성 시점에 필요한 작업을 수행
    • @PreDestroy: 빈 파괴(주로 어플리케이션 종료) 시점에 필요한 작업을 수행

관점 지향 프로그래밍(AOP:Aspect Oriented Programming)

관점지향..? 공통적인 부분을 Spring이 도와서 처리해준다.. 라고 강사님이 설명해주셨다.. 근데 아직은 잘모르겠지만 정리를 하면서 공부해보겠다.
AOP란 특정한 함수 호출전이나 호출후 뭔가 공통적인 처리가 필요하면 AOP를 사용한다
그 예중 로깅, 트랜잭션(스프링 MVC 프로젝트를 하다보면 @Transaction을 붙이게 되는데 내부적으로는 AOP가 대신 공통된 기술을 해준다) ,인증등이 있다.

AOP의 기본 개념

Aspect

여러 클래스나 기능에 걸쳐서 있는 관심사, 그것들을 모듈화함
AOP중에서 가장 많이 활용되는 부분은 @Transactional(트랜잭션관리) 기능

Advice

AOP에서 실제로 적용하는 기능(로깅,트랜잭션,인증 등)을 뜻함

Join Point

프로그램이 진행을 하고 있을때 일련의 흐름들이 이어지고 있을때 모든 흐름에 AOP를 심을 수 없다. 특정 심을 수 있는 point들을 Join Point라고 함
즉, 모듈화된 특정 기능이 실행될 수 있는 연결 포인트

PointCut

Join Point중에서 해당 Aspect를 적용할 대상을 뽑은 조건식이다.

targetObejct

Advice가 적용될 오브젝트

AOP Proxy

대상 오브젝트에 Aspect를 적용하는 경우 Advice를 덧붙이기 위해 하는 작업
주로 CGLIB(Code Generation Library, 실행 중에 실시간으로 코드를 생성하는 라이브러리) 프록시를 사용하여 프록싱 처리를 함

Weaving

Advice를 비지니스 로직 코드에 삽입하는 것을 말함

AspectJ 지원

AOP를 활용할때 주로 사용하는 라이브러리
AOP를 제대로 사용하기 위해 꼭 필요한 라이브러리
기본적으로 Spring boot에 포함이 되어있다.
기본적으로 제공되는 Spring AOP로는 다양한 기법(Pointcut 등)의 AOP를 사용할 수 없음

Aspect 생성

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component  // Component를 붙인 것은 해당 Aspect를 스프링의 Bean으로 등록해서 사용하기 위함
public class UsefulAspect {

}

Pointcut선언

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component  // Component를 붙인 것은 해당 Aspect를 스프링의 Bean으로 등록해서 사용하기 위함
public class UsefulAspect {

	@Pointcut("execution(* transfer(..))")	//- 포인트컷 표현식
	private void anyOldTransfer() {}
}
  • 해당 Aspect의 Advice(실행할 액션)이 적용될 Join point를 찾기 위한 패턴 또는 조건 생성

Pointcut 결합

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component  // Component를 붙인 것은 해당 Aspect를 스프링의 Bean으로 등록해서 사용하기 위함
public class UsefulAspect {

	@Pointcut("execution(public * *(..))")
	private void anyPublicOperation() {} //public 메서드 대상 포인트 컷

	@Pointcut("within(com.xyz.myapp.trading..*)")
	private void inTrading() {} // 특정 패키지 대상 포인트 컷
	
	@Pointcut("anyPublicOperation() && inTrading()")
	private void tradingOperation() {} // 위의 두 조건을 and(&&) 조건으로 결합한 포인트 컷
}

Advice 정의

포인트컷을 활용하여 포인트컷의 전/후/주변에서 실행될 액션을 정의

Before Advice(전)

dataAccessOperation()이라는 미리 정의된 포인트 컷의 바로 전에 doAccessCheck가 실행

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class BeforeExample {

    @Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }
}

After Returning Advice(후)

dataAccessOperation()라는 미리 정의된 포인트컷에서 return이 발생된 후 실행
로깅, 알림을 보내는 것들이 필요할 수 있다

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;

@Aspect
public class AfterReturningExample {

    @AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }
}

Around Advice

특정 서비스(여기서는 businessService()라는 포인트컷 전/후에 필요한 동작을 추가함)

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
public class AroundExample {

    @Around("com.xyz.myapp.CommonPointcuts.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        // start stopwatch
        Object retVal = pjp.proceed();	//-ProceedingJoinPoint(우리가 잡아둔 포인트컷)의 메소드를 실행함
        // stop stopwatch
        return retVal;
    }
}

Validation,Data binding에대해서 알아보기

Validation in Spring

Validation이란?

유효성검증이라고하며 주로 사용자또는 서버의 요청(http request)내용에서 잘못된 내용이 있는 지 확인하는 단계를 뜻한다

Validation 종류

데이터검증

  • 필수 데이터 존재 유무
  • 문자열의 길이나 숫자형 데이터의 경우 값의 범우
  • email,신용카드 번호등 특정형식에 맞춘 데이터

비지니스 검증

  • 서비스 정책에 따라 데이터를 확인하여검증
    예를 들어 배달앱인 경우 배달요청시 해당 주문건이 결제 완료 상태인지 확인하는 예시가 있다
  • 경우에 따라 외부 API 호출하거나 DB의 데이터까지 조회하여 검증하는 경우도 존재함

Spring의 Validation

스프링은 웹 레이어에 종속적이지 않은 방법으로 밸리데이션을 하려고 의도하고 있으며 주로 아래 두가지 방법을 활용하여 밸리데이션 진행(둘다 데이터 검증에 가까움)
비지니스 검증은 스프링이 도와줄수없는 레이어라고 하셨다

Java Bean Validation

JavaBean 기반으로 간편하게 개별데이터를 검증이며 요즘에 가장 많이 활용되는 방법중하나로
JavaBean내에 어노테이션으로 검증방법을 명시한다

public class MemberCreationRequest {
		@NotBlank(message="이름을 입력해주세요.")
		@Size(max=64, message="이름의 최대 길이는 64자 입니다.")
    private String name;
		@Min(0, "나이는 0보다 커야 합니다.")
    private int age;
		@Email("이메일 형식이 잘못되었습니다.")
    private int email;

    // the usual getters and setters...
}

name, age,email이라는 세개의 property가 있다 그리고 각각 프로퍼티내에 검증 내용들을 어노테이션으로 명시해뒀다 이렇게 간단하게 에노테이션을 붙여두면 심플하게 Validation이 가능해진다.
위처럼 요청 dto에 어노테이션으로 명시 후 아래처럼 @Valid 어노테이션을 해당 @RequestBody에 달게 되면, Java Bean Validation을 수행한 후 문제가 없을 때만 메서드 내부로 진입이 된다.

@PostMapping(value = "/member")
public MemeberCreationResponse createMember(
	@Valid @RequestBody final MemeberCreationRequest memeberCreationRequest) {
	// member creation logics here...
}

검증중에 실패가 발쌩하면 MethodArgumentNotValidException이 발생

Spring Validator를 인터페이스 구현을 통한 validation

Person이라는 객체를 Javabean으로 만들어 두는 예시가 있다.

public class Person {

    private String name;
    private int age;

    // the usual getters and setters...
}
public class PersonValidator implements Validator {

    /**
     * This Validator validates only Person instances
     */
    public boolean supports(Class clazz) {
        return Person.class.equals(clazz);
    }

    public void validate(Object obj, Errors e) {
        ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
        Person p = (Person) obj;
        if (p.getAge() < 0) {
            e.rejectValue("age", "negativevalue");
        } else if (p.getAge() > 110) {
            e.rejectValue("age", "too.darn.old");
        }
    }
}

Validator라는 인터페이스를 구현하여 해당 Person이라는 해당 인스턴스에만 활용되는 validator를 만든 예제이다
인터페이스의 두메서드는 아래와 같은 역할을한다

  • supports메서드: 이 validator가 동작할 조건을 정의하며 주로 class의 타입을 비교한다

  • validate메서드: 객체의 이름, 나이를 비교하는 validate를 진행한다

    Javabean validation을 주로 사용한다고 강사님께서 말씀하심

Validation 수행시 주의사항 및 패턴

주의사항

  • validation이 여러군데 흩어져 있으면 테스트및 유지보수성이 떨어짐
    - 정책변경시에 모든 중복코드를 수정해야하고 중복된 검증이 있을 수 있다
    - 여러군데서 다른 정책을 따르는 검증이 수행될 수 있다.
    즉 가능한 validation은 로직초기에 수행하고 실패시 exception을 던지는 편이 처리하기가 편리하다

실무활용 패턴

  • 강사님이 주로사용하는 패턴
    요청(request)dto에서 Java bean Validation에서 단순데이터(유무,범위,형식등)을 1차로 검증후
    로직 초기에 2차로 비지니스 검증 수행후 실패시엔 Custom Exception(ErrorCode,ErrorMessage)를 해서 예외를 던져서 예외처리를 응답 생성하는 것을 주로하신다고 하셨다

Spring validator의 장단점

장점: JavaBean Validation에 비해 조금더 복잡한 검증이 가능하다 예를 들어 두개의 데이터를 비교해서 검증한다던가
단점 : Validation을 수행하는 코드가 JavaBean Validation에 비해 찾기가 어렵다,
완전히 데이터만 검증하는 것이 아니기 때문에 일부 비즈니스적인 검증이 들어가는 경우가 있음
→ 이 경우 비즈니스 검증 로직이 여러 군데로 흩어지기 때문에 잘못된 검증(중복 검증, 다른 정책을 따르는 검증)을 수행할 가능성이 높아짐

Data Binding

사용자나 외부 서버의 요청 데이터를 특정 도메인 객체에 저장해서 우리 프로그램에 Request에 담아주는 것을 뜻한다. 이때 사용되는 내부원리에 대해서 간단히 알아보자

Converter<S,T> Interface

S(Source)라는 타입을 받아서 T(Target)이라는 타입으로 변환해주는 Interface임

package org.springframework.core.convert.converter;

public interface Converter<S, T> {

    T convert(S source);
}

이 인터페이스는 강사님이 사용한 경험은 파라미터에 json형식의 문자열이 담겨오는 경우 해당 문자열을 곧바로 특정 dto를 담고싶을때 사용했다

// 요청
GET /user-info
x-auth-user : {"id":123, "name":"Paul"}	//-json형식으로 id,name이 넘어온다

// 유저 객체
public class XAuthUser {
    private int id;
    private String name;

    // the usual getters and setters...
}

@GetMapping("/user-info")
public UserInfoResponse getUserInfo(
	@RequestHeader("x-auth-user") XAuthUser xAuthUser){

	// get User Info logic here...
}

헤더에 json형식으로 담긴 문자열을 XAuthUser객체에 바로 담고싶은 경우 Converter를 사용하는 것이 좋다
Converter를 아래와 같이 Bean으로 등록하면된다

@Component	//-Converter를 아래와 같이 Bean으로 등록하면된다
public class XAuthUserConverter implements Converter<String, XAuthUser> {
	@Override
	public XAuthUser convert(String source) {
		return objectMapper.readValue(source, XAuthUser.class);
	}
}

Json은 String형이고 이 값들을 XAuthUSer로 변환해준다
이와 비슷하게 PathParameter나 기타 특수한 경우 데이터를 특정 객체에 담고 싶은 경우
1. Converter를 만들어서 Spring에 Bean으로 등록
2. 스프링 내 ConversionService라는 내장된 서비스로 Converter 구현체 Bean들을 Converter리스트에 등록
3. 외부데이터가 들어오고 , Source Class Type-> Target Class Type이 Converter에 등록된 형식과 일치하면 해당 Converter가 동작하는 원리
이러한 과정을 통해 requestbody에 특정한 문자열(JSON)이 들어왔을때 Bean에 등록된 Converter가 우리의 requestDTO에 담기게 되는것이다.

Formatter

특정 객체 와 String간의 변환을 담당(Converter의 일종이라고 생각할 수 있다)
Converter와 다른점은 response,request에도 활용을 하는 Converter이다
예시)
아래의 코드는 Date와 String간의 변환을 수행하는 Formatter이다

package org.springframework.format.datetime;

public final class DateFormatter implements Formatter<Date> {
    public String print(Date date, Locale locale) {
        return getDateFormat(locale).format(date);
    }

    public Date parse(String formatted, Locale locale) throws ParseException {
        return getDateFormat(locale).parse(formatted);
    }
		// getDateFormat 등 일부 구현은 핵심에 집중하기 위해 생략... 
}
  • print메소드: API요청에 대한 응답을 줄때, Date형식으로 된 데이터를 특정 locale에 맞춘 String으로 변환
  • parse 메소드: API요청을 받아올때 String으로 된 "2022-04-27 13:15:00"같은 날짜 형식의 데이터를 Date형으로 변환하도록한다

Formatter도 Converter와 마찬가지로 Spring Bean으로 등록하면 자동으로 ConversionService에 등록시켜주기 때문에 필요(요청/응답 시 해당 데이터 타입이 있는 경우)에 따라 자동으로 동작하게 된다.

Resource

Spring Resource

java.net.URL의 한계(classpath 내부 접근이나 상대경로 등)를 넘어서기 위해 스프링에서 추가로 구현
java.net.URL은 외부 url접근 기능이 주로있는것이다.
Spring의 내부 동작을 이해하기 위해서 필요한 부분이다.

Spring안의 Resource Interface와 그 구현체들

public interface Resource extends InputStreamSource {

    boolean exists();

    boolean isReadable();

    boolean isOpen();

    boolean isFile();

    URL getURL() throws IOException;

    URI getURI() throws IOException;

    File getFile() throws IOException;

    ReadableByteChannel readableChannel() throws IOException;

    long contentLength() throws IOException;

    long lastModified() throws IOException;

    Resource createRelative(String relativePath) throws IOException;

    String getFilename();

    String getDescription();
}

Spring 내부에서Resource 인터페이스의 구현체 중 대표적인 몇가지

UrlResource

java.net.URL을 래핑한 버전, prefix로 다양한 종류(ftp:, file:, http:, 등의 prefix로 접근유형 판단)의 Resource에 접근 가능하지만 기본적으로는 http(s)로 원격접근

ClassPathResource

스프링 프로젝트를 빌드한 결과물이 특정 폴더로 자동으로 들어가게된다 classpath(소스코드를 빌드한 결과(기본적으로 target/classes 폴더))하위의 리소스 접근시 사용한다

FileSystemResource

특정 파일경로를 딱찝어서 File을 다루기 위한 리소스 구현체

SevletContextResource, InputStreamResource, ByteArrayResource

Servlet 어플리케이션 루트 하위 파일, InputStream, ByteArrayInput 스트림을 가져오기 위한 구현체

Spring ResourceLoader

스프링 프로젝트 내 Resource(파일 등)에 접근할 때 사용하는 기능(인터페이스라고생각하면된다)
기본적으로 applicationContext에서 구현이 되어 있다.
프로젝트 내 파일(주로 classpath 하위 파일)에 접근할 일이 있을 경우 활용한다
대부분의 사전정의된 파일들은 자동으로 로딩되도록 되어 있으나, 추가로 필요한 파일이 있을 때 이 부분 활용 가능

applicationConterxt는 스프링의 핵심 기능들이 집약되어있는 모듈이다 즉 스프링의 뇌, 코어이다

@Service
public class ResourceService {

	@Autowired
	ApplicationContext ctx;	//-@Autowired를 통해 ResourceService가 JavaBean에 등록이 될때 ApplicationContext를 ctx라는 property에 Injection(주입)을 하게된다 

	public void setResource() {
		Resource myTemplate = 
			ctx.getResource("classpath:some/resource/path/myTemplate.txt");
			// ctx.getResource("file:/some/resource/path/myTemplate.txt");
			// ctx.getResource("http://myhost.com/resource/path/myTemplate.txt");
		// use myTemplate...
	}
}

ResourcePatternResolver

Spring의 두뇌라고하는 ApplicaitonContext의 인터페이스에 가장 중요한 기능하나가 ResourcePatternResolver이다
스프링 ApplicationContext에서 ResourceLoader를 불러올 때 사용하는 Interface

위치 지정자 패턴("classpath:", "file:", "http:")에 따라 자동으로 Resouce 로더 구현체를 선택

public interface ApplicationContext extends EnvironmentCapable, 
		ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
		// Spring ApplicationContext interface
}

Apllication Contexts & Resource Paths

applicationContext(스프링의 핵심설정)을 이루는 설정값을 가져오는 방법들

// let's create an applicationContext
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");

ApplicationContext ctx =
    new FileSystemXmlApplicationContext("conf/appContext.xml");

ApplicationContext ctx =
    new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");


// then you can use ctx as a Spring
Bear bear = (Bear) ctx.getBean("bear");

Spring Expression Language(SpEL)

SpEL(Spring Expression Language)

Expression Language(표현언어)는 짧고 간단한 문법을 통해 필요한 데이터설정 값을 얻어올 수 있게 하는 특별한 형태의 표현식에 가까운 간편한 언어(그래프 접근 등 가능)
SpEL은 그 중에서도 스프링 모든 영역에서 사용 가능한 언어형식임
주로 @Value라는 어노테이션에 설정값을 주입받는데 활용받는다

@Value("${config.value}")

이러한것들을 어떻게 가져오는 지 간단하게 알아보자

SpEL의 값 평가(evaluation) 즉, 거기안에 있는 값을 한번 실행시켜본다

SpelParser는 ""안에 있는 문자열을 평가(evaluation)해서 결과값을 만들어낸다

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'"); 
String message = (String) exp.getValue();  // "Hello World"

Expression expWow = parser.parseExpression("'Hello World'.concat('!')"); 	//-스프링의 메서드(concat)까지도 쓸수있다.
String messageWow = (String) expWow.getValue();  // "Hello World!"

Expression expString = 
	parser.parseExpression("new String('hello world').toUpperCase()"); //-String 객체를 new로 생성해서 사용도 가능하다
String messageString = expString.getValue(String.class); // "HELLO WORLD"

'Hello World'는 문자열 리터럴이 되며,concat이라는 메서드도 호출할 수 있다
String 객체를 new로 생성해서 사용도 가능하다
이런식으로 Experssion Language안에 문자뿐만아니라 좀더 복잡한 메소드 호출, 그리고 객체생성해서도 사용가능하다라고 생각하면된다.
굳이 이렇게 한번더 복잡하게 할 이유가 없다 실무적으로 쓰는경우는 아래와같다

Bean으로 Property를 설정할 때 사용하는 방식

기본적으로 #{ } 방식으로 property를 설정
$표시를 사용했을경우 application.properties(또는 application.yml)의 값을 가져올 때는 ${ } 방식으로 가져올 수 있다.

@Component
public class SimpleComponent {
	@Value("#{ 1+1 }")
	int two; // 2

	@Value("#{ 2 eq 2 }")
	boolean isTrue; // true

	@Value("${ server.hostname }")
	String hostName; // www.server.com

	@Value("#{ ${ server.hostname } eq 'www.server.com'}")
	boolean isHostSame; // true
}

Null Safety

Null Safety

널 안정성을 높이는 방법이다
자바에서는 매번 아래의 코드처럼 Null체크를 해야한다

public void method(String request) {
	if(request == null) return;

	// normal process
	System.out.println(request.toUpperCase());
}  

Null Safety에서는 위와 같은 코드(보일러플레이트; 맨날 똑같은 코드가 반복적으로 생기는거)를 만들지 않으며 혹은 널체크하지 않아서 NPE(Null Pointer Exception)을 방지하는 방법이며 완벽한 방법은 아니지만 IDE에서 경고를 표시함으로 1차적인 문제를 방지하고 정확한 에러 위치를 확인할 수 있도록 도와준다

@NonNull Annotation을 통해 Null Safety를 구현할 수 있다.

해당 값이나 함수 등이 Null이 아님을 나타내는 어노테이션
org.springframework.lang.NonNull 사용

메서드 파라미터에 붙이는 경우 : null이라는 데이터가 들어오는 것을 사전에 방지함 어떤 메서드에서 NPE이 발생햇는지 알수있다.

프로퍼티에 붙이는 경우는 null을 저장하는 경우 경고를 보여준다

메서드에 붙이는 경우 : null을 리턴하는 경우 경고, 응답값을 저장하거나 활용하는 쪽도 NonNull이라고 신뢰하고 사용

@Nullable Annotation

@NonNull과 반대로 해당 데이터가 null일수 있음을 명시
해당 어노테이션이 붙은 값을 사용하는 경우 null check를 항상 수행하도록 경고한다

profile
주니어 개발자 되고싶어요

0개의 댓글