![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/c5LcN1/btr3eftZKYf/UCxYc7uGG40MiEz6Kn4Rk1/img.png)
과거에는 톰캣 같은 WAS를 별도로 설치하고, IDE에 복잡한 설정을 거쳐 개발이 완료된 코드를 WAR로 만들고 이것을 또 WAS에 전달해서 배포하는 과정이 필요했다. 하지만 스프링 부트는 WAS가 라이브러리로 jar 내부에 포함되어 있기 때문에 복잡한 설정이 필요 없고, 배포는 JAR로 만들어서 원하는 위치에서 실행하기만 하면 된다. 간단한 프로젝트를 통해 스프링 부트가 어떻게 톰캣 서버를 내장해서 실행하는지 알아보자! build.gradle plugins { id 'java' id 'org.springframework.boot' version '3.0.2' id 'io.spring.dependency-management' version '..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/bhtedi/btr3ar1rtsw/xEWgx2PEqUIbktnIHEkCd0/img.png)
외장 서버 VS 내장 서버 전통적인 방식(외장 서버) 과거에 자바로 웹 애플리케이션을 개발할 때는 먼저 서버에 톰캣 같은 WAS(웹 애플리케이션 서버)를 설치했다. WAS에서 동작하도록 서블릿 스펙에 맞추어 코드를 작성하고, WAR 형식으로 빌드해서 war 파일을 만든 뒤, war 파일을 WAS에 전달해서 배포하는 방식으로 전체 개발 주기가 동작했다. WAS 기반 위에서 개발하고 실행해야 하기 때문에 IDE 같은 개발 환경에서도 WAS와 연동해서 실행되도록 복잡한 추가 설정이 필요하다. 최근 방식(내장 서버) 최근에는 스프링 부트가 내장 톰캣을 포함하고 있다. 애플리케이션 코드 안에 톰캣 같은 WAS가 라이브러리로 내장되어 있다는 뜻이다. 개발자는 코드를 작성하고 JAR로 빌드한 다음에 해당 JAR를 원..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/bjUgPO/btrRVuWMcGu/TM6VqH1wmjV5MyUL1uNPpk/img.png)
이번에는 REQUIRES_NEW를 사용해서 문제 상황을 가정하고 해결해보도록 하자. 문제 상황 회원가입에 성공하면 회원 DB와 회원 이력 로그 DB에 저장하는 비지니스 로직을 수행해야 한다. 회원가입과 이력 로그를 저장하는 로직을 하나의 트랜잭션으로 묶어서 처리하던 중, 만약 이력 로그 저장에서 문제가 발생하면 회원가입 자체가 안 되는 상황이 발생한다. 실제 비지니스에서 이런 상황이 발생하면 많은 회원들이 이탈하는 문제가 발생할 것이기 때문에 요구 사항이 변경 되었다. "회원 가입을 시도한 로그를 남기는데 실패하더라도 회원 가입은 유지되게 해주세요." 단순하게 생각해보면 LogRepository에서 예외가 발생하면 그것을 MemberService에서 예외를 잡아서 처리하면 될 것 같다. 이렇게 하면 Me..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/tfyFX/btrRMZpGcLD/tIkL3yX3nFkInmtXwAebsK/img.png)
REQUIRES_NEW는 외부 트랜잭션과 내부 트랜잭션을 완전히 분리해서 각각 별도의 물리 트랜잭션을 사용하는 방법이다. 그렇기 때문에 커밋과 롤백도 각각 별도로 이루어지게 된다. 이 방법은 각각 독립된 트랜잭션이기 때문에, 내부 트랜잭션에 문제가 발생해서 롤백 되더라도 기본 설정인 REQUIRED처럼 외부 트랜잭션에는 영향을 주지 않는다. 반대로 외부 트랜잭션에 문제가 발생해도 내부 트랜잭션에 영향을 주진 않는다. 아래 예제를 보면서 작동 원리를 이해해보자! Test Code @Test void inner_rollback_required_new() { log.info("외부 트랜잭션 시작"); TransactionStatus outer = txManager.getTransaction(new Defaul..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/pfTih/btrPOjwNhou/0sddUC5dcQnE7zbAeazOdK/img.png)
@Transactional을 적용하면 프록시 객체가 요청을 먼저 받아서 트랜잭션을 처리하고, 실제 객체를 호출해준다. 때문에 트랜잭션을 적용하려면 항상 프록시를 통해서 대상 객체(Target)을 호출해야 한다. 이렇게 해야 프록시에서 먼저 트랜잭션을 적용하고, 이후에 대상 객체를 호출하게 된다. 만약 프록시를 거치지 않고 대상 객체를 직접 호출하게 되면 AOP가 적용되지 않고, 트랜잭션도 적용되지 않는다. AOP를 적용하면 스프링은 대상 객체 대신에 프록시를 스프링 빈으로 등록한다. 따라서 스프링은 의존관계 주입시에 항상 실제 객체 대신에 프록시 객체를 주입한다. 프록시 객체가 주입되기 때문에 대상 객체를 직접 호출하는 문제는 일반적으로 발생하지 않지만, 대상 객체의 내부에서 자신의 다른 메서드 호출이 ..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/cC1SbE/btrKIyqWPto/H3TzSzl5fIwO0GwRXphBvk/img.png)
웹 서버 (Web Server) HTTP 기반으로 동작하는 웹 서버는 보통 정적 리소스(HTML, CSS, JS, Image 등)를 제공한다. 예로 NGINX와 APACHE가 있다. 웹 어플리케이션 서버 (WAS) 웹 어플리케이션 서버(WAS) 역시 HTTP 기반으로 동작하며, 웹 서버의 기능도 포함하기 때문에 정적 리소스를 제공할 수 있다. 사용자의 요청이 들어오면 프로그램 코드를 실행해서 애플리케이션 로직을 수행한 후, 그 결과를 HTML이나 HTTP API(JSON)으로 제공한다. 예로 Tomcat, Jetty, Undertow가 있다. 웹 서버와 웹 어플리케이션의 차이 간단하게 살펴보면 웹 서버는 정적 리소스(파일)를 제공하고, WAS는 어플리케이션 로직까지 실행할 수 있다는 점이다. 하지만 웹 ..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/Dc92k/btrD7EKIqv7/T6OsXftFcAiOTSOMMUeMN0/img.png)
@target vs @within @target은 인스턴스의 모든 메서드를 조인 포인트로 적용하고, @within은 해당 타입 내에 있는 메서드만 조인 포인트로 적용한다. 이를 풀어서 이야기하면, @target은 부모 클래스의 메서드까지 어드바이스를 다 적용하고, @within은 자기 자신의 클래스에 정의된 메서드에만 어드바이스를 적용한다는 것이다. Test code @Slf4j @Import({AtTargetAtWithinTest.Config.class}) @SpringBootTest public class AtTargetAtWithinTest { @Autowired Child child; @Test void success() { log.info("child Proxy={}", child.getClas..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/Bw5Cg/btrDE8fjQto/g8ZYdK1AufHYuXpkkgMKLk/img.png)
포인트컷 지시자 포인트컷 표현식은 execution같은 포인트컷 지시자(Pointcut Designator)로 시작한다. 줄여서 PCD라 한다. 포인트컷 지시자 종류 execution : 메소드 실행 조인 포인트를 매칭한다. 스프링 AOP에서 가장 많이 사용하고, 기능도 복잡하다. within : 특정 타입 내의 조인 포인트를 매칭한다. args : 인자가 주어진 타입의 인스턴스인 조인 포인트 this : 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트 target : Target 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트 @target : 실행 객체의 클래스에 주어진 타입의 애노테이션이 있는 조인 포인트 @within : 주어진 애노테이션이 있는 ..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/Gbdnm/btrDlj3rpY8/AAeqKcHUrdNYnr3KbO7dL0/img.png)
Advice 종류 @Around : 메서드 호출 전후에 수행, 가장 강력한 어드바이스, 조인 포인트 실행 여부 선택, 반환 값 변환, 예외 변환 등이 가능 @Before : 조인 포인트 실행 이전에 실행된다. @AfterReturning : 조인 포인트가 정상 완료후 실행된다. @AfterThrowing : 메서드가 예외를 던지는 경우 실행된다. @After : 조인 포인트가 정상 또는 예외에 관계없이 실행(finally)된다. 아래 예제를 살펴보면서 좀 더 깊이 학습해보자! @Slf4j @Aspect public class AspectAdvice { @Around("com.hyuuny.advanced.order.aop.Pointcuts.orderAndService()") public Object doT..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/bTDSBZ/btrC2Zv5IXa/LJLQGmbHjwmOjBxVKNN7Gk/img.png)
AOP 용어는 보고 또 봐도 낯설기만하다. 이 기회에 AOP 용어를 정리해보자! 조인 포인트(Join point) 어드바이스가 적용될 수 있는 위치(메서드 실행 지점, 생성자 호출, 필드 값 접근, static 메서드 접근 등) 조인 포인트는 추상적인 개념이다. AOP를 적용할 수 있는 모든 지점이라 생각하면 된다. 스프링 AOP는 프록시 방식을 사용하므로 조인 포인트는 항상 메소드 실행 지점으로 제한된다. 포인트컷(Pointcut) 조인 포인트 중에서 어드바이스가 적용될 위치를 선별하는 기능 주로 AspectJ 표현식을 사용해서 지정 프록시를 사용하는 스프링 AOP는 메서드 실행 지점만 포인트컷으로 선별 가능 타켓(Target) 어드바이스를 받는 객체 어드바이스(Advice) 부가 기능 특정 조인 포인..
- Total
- Today
- Yesterday
- 백준
- 자료구조
- 구현
- kotlin
- mysql 8.0
- 인프런
- 노마드
- 코틀린
- 리팩토링
- 스프링부트
- 정렬
- 그리디
- 데이터베이스
- Spring
- 김영한
- 파이썬
- MySQL
- 북클럽
- 스프링 부트
- spring boot
- webflux
- Real MySQL
- 코테
- 알고리즘
- Algorithm
- 노마드코더
- 스프링
- leetcode
- 릿코드
- 문자열
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |