CompletionStage 인터페이스

ForkJoinPool - thread pool

  • CompletableFuture은 내부적으로 비동기 함수들을 실행하기 위해 ForkJoinPool을 사용
  • ForkJoinPool의 기본 size = 할당된 코어 -1
  • 데몬 쓰레드
    • main 스레드가 종료되면 즉각적으로 종료

ForkJoinPool - fork & join

  • Task를 fork를 통해서 subtask로 나누고
  • Thread pool에서 steal work 알고리즘을 이용해서 균등하게 처리
  • join을 통해서 결과를 생성

CompletionStage 연산자

CompletionStage 연산자 조합

  • 50개에 가까운 연산자들을 활용하여 비동기 task들을 실행하고 값을 변형하는 등 chaining을 이용한 조합 가능
  • 에러를 처리하기 위한 콜백 제공

then**[Async] 차이

  • stage에 상태에 따라 caller 쓰레드에서 action을 수행 하거나 callee 쓰레드에서 action을 실행 하는 등 파악하기 어렵다.
  • 하지만 then**Async에서는 thread pool에 있는 쓰레드에서 action을 실행(항상)
  • 모든 then**Async 연산자는 executor를 추가 인자로 받는다.
    • 이를 통해 다른 쓰레드풀로 task를 실행할 수 있다.

thenAccept[Async]

  • Consumer를 파라미터로 받는다.
  • 이전 task로부터 값은 받지만 넘기지 않는다.
  • 다음 task에게 null이 전달된다.
  • 값을 받아서 action만 수행하는 경우 유용

thenApply[Async]

  • Function을 파라미터로 받는다.
  • 이전 task로부터 T 타입의 값을 받아서 가공하고 U타입의 값을 반환한다.
  • 다음 task에게 반환했던 값이 전달된다.
  • 값을 변형해서 전달해야 하는 경우 유용

thenCompose[Async]

  • Function을 파라미터로 받는다.
  • 이전 task로 부터 T타입을 받아서 가공하고 U타입의 ComletionStage를 반환한다.
  • 반환한 CompletionStage가 done 상태가 되면 값을 다음 task에 전달한다.
  • 다른 future를 반환해야하는 경우 유용

thenRun[Async]

  • Runnable을 파라미터로 받는다.
  • 이전 task로부터 값을 받지 않고 값을 반환하지 않는다.
  • 다음 task에게 null이 전달된다.
  • future가 완료되었다는 이벤트를 기록할 때 유용

exceptionally

  • Function을 파라미터로 받는다.
  • 이전 task에서 발생한 exception을 받아서 처리하고 값을 반환한다.
  • 다음 task에게 반환된 값을 전달한다.
  • future 파이프에서 발생한 에러를 처리할 때 유용

 

캡슐화란?

  • 캡슐화는 객체가 내부적으로 기능을 어떻게 구현하는지를 감추는 것이다.
  • 단순히 프라이빗한 데이터를 직접 데이터를 직접 접근하지 못하게 하기 위해 사용하는 것이 아닌 내부적인 기능에 초점을 맞춰야 한다. 단순히 데이터를 접근하기 위한 용도로 캡슐화를 사용한다면 객체에 대한 책임이 분산될 수 있다.

캡슐화를 하기 위한 두가지 규칙

묻지 말고 시켜라

  • 참조한 객체의 데이터에 대한 로직이 필요할 경우에 직접 구현하지 말고 구현된 데이터를 요청하여 데이터에 대한 책임을 전가 시킬 수 있다.

데미테르의 법칙

  • 1 뎁스만 사용할 뿐 2뎁스로 사용하지 말아야 한다. 이것은 묻지 말고 시켜라의 연장선으로 참조하는 객체가 가지고 있는 데이터를 참조하는 사용자 입장에서는 알 필요가 없고 데이터를 사용하여 데이터의 내부 기능을 사용하게 되면 내부 기능의 변화에 범위가 외부에도 노출되어 의존성이 낮아진다.

'Computer science > 디자인패턴 및 프로그래밍 패러다임' 카테고리의 다른 글

SOLID 원칙  (0) 2023.06.30
상속과 합성  (0) 2023.06.30
객체지향과 절차지향  (0) 2023.06.30
싱글톤 패턴  (0) 2022.12.15

단일 책임 원칙(Single Responsibility Principle , SRP)

  • 객체는 단 하나의 책임만을 가져야 한다. 책임이 많아지면 클래스 내부의 함수끼리 강한 결합을 발생할 가능성이 높아지며 이는 유지보수에 비용이 증가하게 되므로 책임을 분리시킬 필요가 있다.

개방 폐쇄 원칙(Open Closed Principle, OCP)

  • 기존의 코드를 변경하지 않고 기능을 수정하거나 추가할 수 있도록 설계해야 한다.
  • OCP를 만족한 설계는 변경에 유연하므로 유지보수 비용을 줄여주고 코드의 가독성 또한 높아지는 효과를 얻을 수 있다.

리스코프 치환 원칙(Liskov Substitution Principle, LSP)

  • 자식 클래스는 부모 클래스에서 가능한 행위를 수행할 수 있어야 한다.
  • 상속 관계에서는 일반화 관계(IS-A)가 성립해야 한다. 일반화 관계에 있다는 것은 일관성이 있다는 것이다.

인터페이스 분리 원칙(Interface Segregation Principle, ISP)

  • 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다. 하나의 일반적인 인터페이스 보다는 여러개의 구체적인 인터페이스가 낫다. 자신이 사용하지 않는 기능에는 영향을 받지 말아야 한다.

의존 역전 원칙(Dependency Inversion Principle)

  • 의존 관계를 맺을 때 변화하기 쉬운 것 보단 변화하기 어려운 것에 의존해야 한다. 의존관계를 맺을 때 구체적인 클래스보다 인터페이스나 추상 클래스와 관계를 맺는 게 변화에 유연하게 대처할 수 있다.

'Computer science > 디자인패턴 및 프로그래밍 패러다임' 카테고리의 다른 글

캡슐화  (0) 2023.06.30
상속과 합성  (0) 2023.06.30
객체지향과 절차지향  (0) 2023.06.30
싱글톤 패턴  (0) 2022.12.15

상속이란?

  • 자식 클래스가 부모클래스를 상속받아 설계된 구조를 일컫는다. 상속으로 이루어진 관계에서는 부모 클래스의 멤버 변수나 메서드를 사용할 수 있다.

자식 클래스는 부모 클래스의 모두 접근이 가능한가?

  • 모두 접근이 가능한 것은 아니다. 부모 클래스의 멤버 변수나 메서드의 접근자가 private가 아닌 public 이나 protected일 경우메나 사용할 수 있다.

protected 접근자는 왜 사용할까?

  • 우선, public 과 protected의 차이를 살펴보자
    • public 접근자는 외부에 노출이 가능하다.
    • public 접근자는 자식 클래스가 접근할 수 있다.
    • protected 접근자는 외부에 노출되지 않는다.
    • protected 접근자는자식 클래스가 접근할 수 있다.
  • 두 접근자 모두 자식 클래스에게 노출이 되지만 외부에 노출 여부에 차이가 있다.\
  • 변경 가능성이 열려있다는 것을 암시
  • 상속받은 자식 클래스에서 구현을 완성시켜야 한다는 것

상속은 언제 사용해야 할까?

  • SOLID 원칙의 리스코프 치환 원칙을 통해서 해답을 얻을 수 있다.
  • 리스코프 치환 원칙은 상속받은 자식 클래스는 부모 클래스를 대체할 수 있는 경우에만 상속을 해야한다고 명시하고 있다.
  • 자식 클래스가 부모 클래스를 대체할 수 있는 경우는 부모 클래스의 외부로 노출되는 메서드를 자식 클래스에서도 같은 의미로 제공되어야 한다는 것을 의미함. → IS-A 관계가 성립

상속으로 얻을 수 있는 장점은 무엇이 있을까?

  • 상속 관계에서는 외부로부터 다형성을 보장하면서 클래스 내부 구현 코드를 모두 구현하지 않고 공통된 로직을 그대로 사용할 수 있다.
  • 클래스 타입에 따라 변경되는 로직만 일부분 구현하면 된다는 것이 장점
  • 하지만 이러한 장점도 java8 부터 인터페이스의 디폴트 메서드 기능이 나오면서 인터페이스내에서 로직 구현이 가능하여 상속의 장점이 약화되었다고 할 수 있다.

추상 클래스는 왜 사용할까?

  • 추상 클래스는 protected 접근자를 사용하는 이유를 더 명확하게 나타내기 위해서 사용한다고 볼 수 있다.
  • 부모 클래스에서는 변경되는 로직을 abstract로 정의하여 내부 로직은 구현하지 않고 상속받은 자식 클래스에서는 무조건 구현할 수 있게 만들어 변경되어야 할 부분과 변경되지 않을 부분을 더 명확히 구분할 수 있게 되었다.
  • 컴파일 단계에서 자식 클래스가 abstract 메서드를 오버라이딩 하지 않을 경우에는 에러가 발생하므로 런타임 단계에서 발생할 수 있는 예외를 명확하게 확인할 수 있는 장점이 있다.
  • 이러한 추상 클래스를 사용한 대표적인 사례가 템플릿 메서드 패턴이라고 할 수 있다. 템플릿 메서드 패턴은 외부로 노출되는 메서드는 그대로이나 내부에서 변경되는 로직만 별도로 추상화하여 외부에서 필요한 전략을 선택하여 내부 구현만 변경되도록 노출하는 디자인 패턴이다.

잘못된 상속 방법

  • 어떤 이는 상속은 코드를 재사용 하기 위해 사용한다고 주장하기도 한다. 이는 전형적인 상속의 잘못된 사용 사례이다.

코드 재사용을 위해 상속을 하면 어떠한 단점이 있나?

캡슐화를 위반할 수 있다.

  • 부모의 public 메서드는 외부에 노출하기 위한 용도로 사용된다. 그러나 자식 클래스에서도 부모 클래스의 public 메서드는 외부로 노출되기 때문에 자식 클래스에서 의도하지 않는 동작을 수반할 수 있게 되며 캡슐화를 위반하게 된다.

설계가 유연하지 않게된다.

  • 상속으로 인해 결합도가 높아지면 다음과 같은 두 가지 문제점이 발생
    • 하나의 기능을 추가하거나 수정하기 위해 불필요하게 많은 수의 클래스를 추가하거나 수정해야 한다.
    • 단일 상속만 지원하는 언어에서는 상속으로 인해 오히려 중복 코드의 양이 늘어날 수 있다.

합성이란?

  • 합성은 객체가 다른 객체의 참조자를 얻는 방식으로 런타임시에 동적으로 이뤄진다. 이는 보통 has-a 관계라고 일컫는다. 따라서 다른 객체의 참조자를 얻은 후 그 참조자를 이용해서 객체의 기능을 이용하기 때문에 해당 객체의 인터페이스만을 바라보게 됨으로써 캡슐화가 잘 이뤄질 수 있다.

합성은 언제 사용해야 할까?

  • 구현 코드를 재사용하고 싶을 때 사용하면 유리하다. 또한 합성으로 사용된 코드는 사용하는 클래스에 따라 외부로 노출시킬 수 있고 내부로 캡슐화 할 수도 있어 클래스 특성에 맞게 캡슐화를 할 수 있다.
  • 합성을 사용하고 인터페이스 타입을 사용한다면 런타임 시에 외부에서 필요한 전략에 따라 교체하며 사용할 수 있으므로 좀 더 유연한 설계를 할 수 있다.
  • 대표적인 사례가 전략 패턴이다.

합성의 단점은?

  • 합성은 객체 간의 관계가 수직관계가 아닌 수평관계가 된다.
  • 따라서 큰 시스템에서 많은 부분에 걸쳐 합성이 사용될 때 객체나 메서드 명이 명확하지 않으면 코드가 가독성이 떨어지고 이해하기 어려워지게 된다.
  • 합성을 사용할 시 용도에 따라 클래스들을 패키지로 분리하고 각각의 사용 용도가 명확하게 드러나도록 인터페이스를 잘 설계해야 한다.

결론

  • 상속을 사용하고 싶다면 단순히 코드를 재사용 하는 용도가 아닌 부모 클래스를 대체할 수 있는 IS-A 관계인지 고려해야 한다. IS-A 관계에서도 변경되는 부분이 있다고 하면 protected 접근자나 abstract 를 사용하여 자식 클래스에게 명확하게 전달해야 한다.
  • 단순히 코드를 재사용하고 싶다면 합성을 고려해보자 합성을 사용하면 코드 재사용도 가능할 뿐더러 캡슐화도 지킬 수 있다. 또한 다양한 전략에 따라 런타임시에 교체도 가능하여 유연한 설계가 가능하다. 단 합성을 하려는 클래스에 너무 많은 기능들이 정의되어 있거나 합성하는 인터페이스의 기능이 단일 책임보다 많은 책임을 가진 설계라면 분리해야할 필요가 있다.

'Computer science > 디자인패턴 및 프로그래밍 패러다임' 카테고리의 다른 글

캡슐화  (0) 2023.06.30
SOLID 원칙  (0) 2023.06.30
객체지향과 절차지향  (0) 2023.06.30
싱글톤 패턴  (0) 2022.12.15

절차지향

  • 절차지향이란 프로시저로 프로그램을 구성하는 기법이다.
  • 프로시저는 대체로 데이터를 중심으로 구현한다.
  • 단점은 데이터 타입이나 의미를 변경해야 할 때, 함께 수정해야 하는 프로시저가 증가하는 것이다.

객체지향

  • 객체는 자신만의 데이터와 프로시저를 갖는다.
  • 객체는 자신만이 기능을 제공한다.
  • 객체들은 서로 연결되어 다른 객체가 제공하는 기능을 사용할 수 있다.

절차지향 vs 객체지향

설계 방식

  • 절차지향 프로그래밍은 프로그램의 순서와 흐름을 먼저 세우고 필요한 자료구조와 함수들을 설계하는 방식
  • 객체지향 프로그래밍은 자료구조와 이를 중심으로 한 모듈 들을 먼저 설계한 다음 이들의 실행 순서와 흐름을 조합하는 방식

목적

  • 절차지향 언어를 사용한다면, 말 그대로 실행 순서, 즉 절차가 더 중심이 된다.
  • 객체지향 언어를 사용한다면, 필요한 객체들의 종류와 속성등이 더 중점이 된다.

더 나은 설계는?

  • 더 나은 설계란 없고, 비즈니스 모델의 성격에 따라 다를 뿐이다.
  • 객체는 변수와 함수를 추상화 과정을 통해 좀 더 모듈화한 도구에 불과하다. 모듈화 함으로써 객체지향이 지닐 수 있는 강점인 정보은닉화, 상속 및 다형성을 통한 확장성과 재사용, 이를 기반한 생산성과 유지보수의 용이성이 OOP의 진정한 특징이자 정체성일지도 모른다.

'Computer science > 디자인패턴 및 프로그래밍 패러다임' 카테고리의 다른 글

캡슐화  (0) 2023.06.30
SOLID 원칙  (0) 2023.06.30
상속과 합성  (0) 2023.06.30
싱글톤 패턴  (0) 2022.12.15

AOP란?

  • AOP는 공통의 관심사를 추상화해 잘 보관하고 있다가 필요한 곳에 동적으로 삽입하며 적용해주는 기술이다. 이로 인해 핵심 로직과 부가 기능을 분리할 수 있고 각각의 기능은 단일 책임을 가진 코드를 유지할 수 있다.

핵심 로직과 부가 기능이 같이 있다면

  • 두 가지 책임을 가지므로 하나의 책임에 인한 코드 수정은 다른 코드에 side effect가 발생할 수 있다.
  • 두 가지 기능이 접목되어 있어 테스트 코드를 작성하려 할 때도 두가지 기능을 다 고려 해야한다.
  • 비즈니스 로직이 복잡하거나 부가 기능이 추가될수록 유지보수 하기가 어려워진다.
  • 유지보수와 비슷한 맥락으로 기능을 확장하거나 다른 전략으로 기능을 변경하기도 어려워 진다.

AOP를 적용한다면?

  • 코드에는 핵심 로직만 남기고 부가 기능은 별도로 추상화하여 주입 받는 방식으로 리팩토링 할 수 있을 것이다.
  • //대표적인 AOP 방식이 @Transactional 적용 @Transactional public void upgradeLevels() throws Exception { List<User> users = userDao.getAll(); for (User user : users) { if (canUpgradeLevel(user)) { upgradeLevel(user); } } this.transactionManager.commit(status); }

코드를 분리하면 어떤 점이 좋을까?

  • 메서드 또는 클래스는 한 책임을 가질 수 있는 코드를 작성할 수 있고 응집도 높은 코드를 작성할 수 있다.
  • 테스트 코드 또한 비즈니스 로직에 대한 테스트 케이스만 작성하면 된다.
  • 유지보수 측면에서도 비즈니스 로직 수정시에 부가 기능에 대한 side effect는 찾아 볼 수 없게 된다.

프록시란?

  • 자신의 클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장해서 클라이언트의 요청을 받아주는 것(대리인 ,대리자)
  • 사용 목적에 따라
    • 클라이언트가 타깃에 접근하는 방법을 제어하기 위해
      • 프록시 패턴
    • 타깃에 부가적인 기능을 부여 해주기 위
      • 데코레이터 패턴

AOP 용어 정리

  • Target Object
    • 부가 기능을 부여할 대상
  • Aspect
    • AOP의 기본 모듈. 그 자체로 애플리케이션의 핵심 기능을 담고있진 않지만 애플리케이션을 구성하는 중요한 한가지 요소, 부가될 기능을 정의한 Advice와 어드바이스를 어디에 적용할지 결정하는 Pointcut을 함께 가짐
  • Advice
    • 타깃에게 제공할 부가 기능을 담은 모듈. 타깃이 필요없는 순수한 부가 기능. Aspect가 무엇을 언제 할지를 정의하고 있음
  • Join point
    • 프로그램의 실행 내부에서 Advice가 적용될 수 있는 위치
  • Pointcut
    • Advice에 적용할 Joinpoint를 선별하는 작업 또는 그 기능을 정의한 모듈

AOP를 구현하는 방법

  • 컴파일 시점에 코드에 공통 기능 삽입
  • 클래스 로딩 시점에 바이트 코드에 공통 기능 삽입
  • 런타임 시점에 프록시 객체를 생성하여 공통 기능 삽입
    • Spring에서 사용하는 방법

'Computer science > Spring' 카테고리의 다른 글

Stereo Type  (0) 2023.06.22
Spring Security  (0) 2023.06.21
@Controlleradvice,@ExceptionHandler  (0) 2023.06.21
@Transactional  (0) 2023.06.15
영속성 컨텍스트  (0) 2023.06.15

Stereo Type이란?

  • 스프링 컨테이너가 스프링 관리 컴포넌트로 식별하게 해주는 단순한 마커다. 즉 scan-auto-detection과 dependency injection을 사용하기 위해서 사용되는 가장 기본 어노테이션이다.
  • Stereo Type이 범용적으로 많이 사용하게 된 시기는 Spring 2.5부터였다. 그 이전까지는 xml파일에 bean을 등록하여 관리하였다.

그러나 모든 bean들을 xml 파일로 관리하다보니 다른 보일러플레이트 코드와 함께 xml 파일만 비대해지게 될 뿐이었다.

그래서 Spring 2.0에서는 @Repository가 등작하였고, Spring 2.5부터는 @Component, @Controller, @Service, @Configuration등이 등작하면서 Stereo type에 대한 정의가 범용적으로 사용하게 되었다.

@Component

  • 빈으로 간주되어 DI 컨테이너에서 사용할 수 있게 하는 기본 어노테이션이다,.

@Bean과 @Component는 어떤 차이가 있는가?

  • @Component는 클래스 상단에 적으며 그 default로 클래스 이름이 bean의 이름이 된다. 또한 spring에서 자동으로 찾고(@ComponentScan) 관리해주는 bean이다.
  • @Bean은 @Configuration으로 선언된 클래스 내에 있는 메서드를 정의할 때 사용한다. 이 메서드가 반환하는 객체가 bean이 되며 default로 메서드 이름이 bean의 이름이 된다.

@RestController와 @Controller의 차이는?

  • @RestController는 Spring 3.0 에서 추가된 어노테이션으로 RESTful web service를 제공하기 위해 @Controller를 확장한 개념이다. 기능적인 측면에서 보았을 땐 @Controller에 @ResponseBody 어노테이션을 추가된 기능이라고 보면 된다.
  • @ResponseBody 어노테이션의 기능은 결과값을 View를 통해서 출력되지 않고 HTTP Response Body에 직접 쓰여지게 되며 이때 리턴되는 데이터 타입에 따라 MessageConverter 에서 변환이 이뤄진 후 쓰여지게 된다.

@Service

  • Service annotation은 단순히 서비스 레이어에서 사용하는 bean이라는 것을 구분하기 위한 용도로 정의한다. 그러므로 @Component로 대체해도 무방하지만 권장하지는 않는다.

@Repository

  • 검사 되지 않은 예외(DAO 메소드에서 발생)를 Spring DataAccessException으로 변환 할 수 있게 해준다.

@Configuration

  • 한 개 이상의 @Bean 어노테이션으로 정의한 bean 들을 생성하려 할 때 클래스에 정의하는 어노테이션이다.

'Computer science > Spring' 카테고리의 다른 글

AOP  (0) 2023.06.22
Spring Security  (0) 2023.06.21
@Controlleradvice,@ExceptionHandler  (0) 2023.06.21
@Transactional  (0) 2023.06.15
영속성 컨텍스트  (0) 2023.06.15

Spring Security Process

  1. 사용자가 로그인 정보와 함께 인증 요청(Http Request) 한다.
  2. AuthenticationFilter가 이 요청을 가로채서 UsernamePasswordAuthenticationToken이라는 인증용 객체를 생성한다.
  3. AuthenticationManager의 구현체인 ProviderManager에게 UsernamePasswdAuthenticationToken 객체를 전달한다.
  4. AuthenticationManager에 등록된 AuthenticationProvider에 UsernamePasswordAuthenticationToekn 객체를 전달한다.
  5. 실제 데이어베이스에서 사용자 인증정보를 가져오는 UserDetailService에 사용자 정보를 넘겨주게 된다.
  6. 넘겨받은 사용자 정보를 통해 DB에서 찾은 사용자 정보인 UserDetails 객체를 생성한다. 이 때 UserDetails는 인증용 객체와 도메인용 객체를 분리하지 않고 인증용 객체에 상속해서 사용하기도 한다.
  7. AuthenticationProvider는 UserDetails를 넘겨받고 사용자 정보를 비교한다.
  8. 인증이 완료되면 권한 등의 사용자 정보를 담은 Authentication 객체를 반환한다.
  9. 다시 최초의 AuthenticationFilter에 Authentication 객체가 반환된다.
  10. Authentication 객체를 SecurityContext에 저장한다.
  11. 최종적으로 SecurityContextHolder는 세션 영역에 있는 SecurityContext에 Authentication 객체를 저장한다. 세션에 사용자 정보를 저장한다는 것은 스프링 시큐리티가 전통적인 세션-쿠키 기반의 인증 방식을 사용한다는 것을 의미한다.

모든 절차는 동일한가?

  • 모든 절차는 동일하지 않다. Filter를 구현하지 않고 RequestMatcher를 통해 바로 AuthenticationManager에게 요청값을 그대로 전달할 수 도 있다. 또는, UserDetailsService의 역할을 ProviderManager가 직접 수행하는 경우도 있다.

AuthenticationManager는 왜 필요하나?

  • 프로세스를 살펴보면 실제로 AuthenticationManager는 직접 수행하는 로직은 없고 등록된 ProviderManager를 통해서 직접적인 인증 처리를 구현하고 있다. 그러므로 AuthenticationManager를 거치지 않고 Provider Manager를 직접 수행해도 문제가 되지는 않는다.
  • 하지만 AuthenticationManager를 거치게 되면 요청값에 따라 다양한 ProviderManager를 분기처리가 가능하다. 또한 한 종류의 ProviderManager를 사용한다고 하더라도 애플리케이션이 추후에 인증 절차가 변경된다고 하더라도 ProviderManager만 교체 하게되면 별도의 코드 수정은 필요하지 않게 된다.

'Computer science > Spring' 카테고리의 다른 글

AOP  (0) 2023.06.22
Stereo Type  (0) 2023.06.22
@Controlleradvice,@ExceptionHandler  (0) 2023.06.21
@Transactional  (0) 2023.06.15
영속성 컨텍스트  (0) 2023.06.15

에외처리

예외 처리의 방법

  • 예외 복구
    • 예외가 발생하면 예외 상황에 대해 알맞게 처리하여 복구한다.(try catch)
  • 예외 회피
    • 예외를 직접 처리하지 않고 예외를 상위 메서드에 위임한다.(throw)
  • 예외 전환
    • 예외를 위임하되 발생한 예외를 그대로 위임하는 것이 아닌 적절한 예외로 전환하여 위임한다.(restTemplate.doExcute)

예외 복구 범위

  • 메서드 영역
    • 메서드 영역은 종속된 복구 기능으로 단순히 try catch 사용하면 된다.
  • 클래스 영역
    • 클래스 내 공통 예외 복구는 @ExceptionHandler 사용할 수 있다.
  • 전역 영역
    • @ControllerAdvice 사용할 수 있다.

컨트롤러 내 예외처리

  • 특정 컨트롤러 내부에서 예외를 처리하고 싶을 경우 @ExceptionHandler를 사용하여 해결하자 이는 @Controller 나 @RestController 빈 내에서 발생하는 특정 예외를 처리해주는 기능을 지원한다.
@ExceptionHandler({NullPointerException.class, ClassCastException.class})
    public String handle(Exception ex){
        return "Exception Handle!!!";
    }

글로벌 예외처리

  • 특정 컨트롤러가 아닌 여러 컨트롤러로 공통된 로직을 구현하기 위해서 @ControllerAdvice를 사용할 수 있다.
  • @ControllerAdvice
    • @ControllerAdvice는 컨트롤러를 보조해주는 기능을 제공한다는 것을 명시한다.
    • @RestControllerAdvice public class ControllerSupport { @ExceptionHandler({NullPointerException.class, ClassCastException.class}) public String handle(Exception ex) { return "Exception Handle!!!"; } }
  • 컨트롤러 내부에 Exception을 처리하는 로직을 따로 작성하지 않아도 된다.

@RestControllerAdvice와 @ControllerAdvice의 차이는?

  • @ResponseBody의 유무 차이만 있을 뿐이다.

status code에도 어떤 에러인지 명시적으로 내어주고 싶은 경우에 @ResponseStatus를 사용할 수 있다.

@RestControllerAdvice
public class ControllerSupport {

    @ExceptionHandler({NullPointerException.class, ClassCastException.class})
    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
    public String handle(Exception ex) {
        return "Exception Handle!!!";
    }
}

'Computer science > Spring' 카테고리의 다른 글

Stereo Type  (0) 2023.06.22
Spring Security  (0) 2023.06.21
@Transactional  (0) 2023.06.15
영속성 컨텍스트  (0) 2023.06.15
Filter 와 Interceptor  (0) 2023.06.15

Transactional

  • 스프링에서 트랜잭션 처리는 보통 @Transactional 어노테이션을 많이 사용하게 된다.
  • @Transactional은 클래스 또는 메서드에 사용할 수 있으며 @Transactional이 포함된 메서드가 호출될 경우, 프록시 객체가 생성된다.
  • 프록시 객체는 해당 메서드 실행 이전에 PlatformTransactionManager를 사용하여 트랜잭션을 시작하고 결과에 따라 Commit 또는 Rollback한다.

Commit과 Rollback은 어느 경우에 발생하는가?

  • CheckedException or 예외가 없을 때는 Commit
  • UncheckedException이 발생하면 Rollback

@Transactional 우선순위는 어떻게 되는가?

  1. 클래스 메서드
  2. 클래스
  3. 인터페이스 메서드
  4. 인터페이스

주의할 점

@Transactional 어노테이션 같은 경우 Spring AOP를 이용하게 되는데 이 AOP는 기본적으로 DynamicProxy를 이용한다. Dynamic Proxy는 인터페이스 기반으로 동작하기 때문에 인터페이스가 없을 경우 트랜잭션이 동작하지 않는다.

  • 인터페이스 없이 트랜잭션 동작하게 하려면 CGLib Proxy를 이용하면 된다. CGLib Proxy는 클래스에 대한 Proxy가 가능하기 때문에 인터페이스가 없어도 된다.
  • Spring 의 코드 삽입 방법은 크게 2가지 방법이 있습니다.
    • 바이트 코드 생성 (CGLIB 사용)
    • 프록시 객체 사용
  • 2가지 방법중 Spring 은 기본적으로 프록시 객체 사용 이 선택됩니다. 그렇기에 interface 가 반드시 필요합니다.SpringBoot 는 기본적으로 바이트 코드 생성 이 선택됩니다. 그렇기에, 굳이 interface 가 필요없습니다.
  • 만약 개발환경이 SpringBoot 라면 Books 인터페이스 없이 봐도 무방합니다.

@Transactinal은 public method에만 적용된다.

  • @Transactional은 프록시 기반으로 동작하기 때문에 public method가 아니면 동작하지 않는다.

동일한 클래스 내의 호출은 @Transactional이 동작하지 않는다.

  • 프록시 기반으로 동작하기 때문에 외부에서 접근할 때 AOP를 통해서 프록시 객체를 접근할 수 있다. 그러나 클래스 내부에서 다른 메서드를 호출하게 되면 프록시로 접근하지 않고 직접 접근하기 때문에 메서드에 선언해 놓은 @Transactional이 정상적으로 동작하지 않는다.
    • 클래스 내부 메서드를 호출하여 @Transactinal을 동작하게 하고 싶다면?
      • 가장 간단한 방법은 새로운 클래스를 생성하여 메서드를 위임하는 것
      • 클래스 생성이 어렵다면 aspectj를 사

'Computer science > Spring' 카테고리의 다른 글

Spring Security  (0) 2023.06.21
@Controlleradvice,@ExceptionHandler  (0) 2023.06.21
영속성 컨텍스트  (0) 2023.06.15
Filter 와 Interceptor  (0) 2023.06.15
OSIV  (0) 2023.06.08

+ Recent posts