Study · Spring Boot · STEP 4 / 8 · 올릴 때

통에 들어간 OrderService 는 내가 쓴 클래스가 아니라, 그것을 상속한 자식이다

장면

컨트롤러가 주입받은 OrderService 의 클래스 이름을 찍어 봤더니 OrderService$$SpringCGLIB$$0 이 나왔다. 내가 만든 적 없는 이 클래스는 누가, 왜 만들었을까?

아래 재생기의 ▶를 누르면 한 스텝씩 진행된다. 금색 테두리가 지금 이야기하는 곳이고, 캡션이 무슨 일이 일어났는지 말해 준다. 굵게 밑줄 친 말은 누르면 뜻이 나온다. 빨간 딱지는 그때 벌어지는 일의 이름이고, 캡션 바로 위 회색 글자는 지금 스텝이 속한 묶음의 이름이다.

카드 아래 회색 줄은 그 일이 실제로 적혀 있는 소스의 파일 이름 : 줄 번호와 함수 이름이다. 글 안에 (:669)처럼 줄 번호만 적힌 것은 바로 앞에 적은 파일의 그 줄이라는 뜻이다. 캡션 한가운데 박힌 긴 영어 이름과 괄호 속 파일 · 줄 번호도 같다 — 건너뛰고 한글만 읽어도 뜻이 통하게 써 두었다.

장면 · 프록시로 감싼다 0 / 9

3단계에서 orderService가 만들어지던 그 순간을 확대한 장면이다. 내가 쓴 OrderService는 필드 하나(JdbcTemplate)와 메서드 둘뿐이다 — place()는 @Transactional이 붙어 있고 주문을 한 줄 넣은 뒤 개수를 세어 돌려주며, count()는 개수만 센다. ▶를 누르면 이 객체가 통에 들어가기까지 사이에 무엇이 끼는지 9스텝으로 따라간다.

키보드 · ← → 한 스텝 · Space 재생/멈춤 · Home 처음

@Transactional 한 줄이 클래스 하나를 통째로 바꿔 끼운다. 내 코드에는 트랜잭션을 여는 문장이 없는데도 트랜잭션이 열리는 이유가 이것이다. 대신 대가가 있다 — 통에 든 것이 내 클래스가 아니므로, 같은 객체 안에서 this 로 다른 메서드를 부르면 자식을 거치지 않아 트랜잭션이 열리지 않는다. 이 실측에서는 317개 중 감싸인 것이 orderService 하나뿐이었다.

어떻게 확인했나

소스 어디를 보고 적었는지와 무엇을 돌려서 쟀는지를 남긴 자리다. 처음 읽을 때는 건너뛰어도 된다.

  • 클래스 이름 · 부모 클래스 · isCglibProxy · aopProxied 1건은 기동이 끝난 뒤 도는 러너가 찍은 값이다.
  • aspectj 가 없어서 상속으로 감쌌다는 것은 2단계의 조건 검사 결과(ClassProxyingConfiguration 켜짐 · AspectJAutoProxyingConfiguration 꺼짐)와 이어 붙인 것이다. 두 사실은 각각 로그로 확인했지만, 둘을 잇는 「그래서」까지 실험으로 갈라 확인하지는 않았다.
  • 같은 객체 안에서 부르면 트랜잭션이 안 열린다는 것은 이 실측에서 확인한 것이 아니라, 자식이 부모를 감싸는 구조에서 따라 나오는 결과로 적었다.