Deep Dive /Java Web /15-M1

15-M1. Service → Mapper: selectBy…()

MyBatis 경로에서는 서비스가 Mapper 인터페이스 메서드를 호출하고, 실제 실행은 MapperProxy가 가로채서 처리합니다. 즉 이 단계는 서비스의 메서드 호출이 SQL 실행 파이프라인으로 진입하는 첫 관문입니다.


이번 단계의 역할 — 구현이 없는 Mapper 인터페이스를 MapperProxy가 대신 맡는다

Mapper 인터페이스는 선언만 있고 구현이 없습니다. 실제 구현은 MapperProxy가 담당하며, 서비스 호출을 MapperMethod.execute(...)로 연결합니다.


호출 흐름 요약 — mapper 메서드 호출 → MapperProxy.invoke() → MapperMethod.execute()

  1. 서비스가 mapper.select...() 메서드를 호출합니다.
  2. MapperProxy.invoke(...)가 이 호출을 받습니다.
  3. 프록시는 MapperMethod.execute(...)를 실행합니다.
  4. 그 뒤부터는 SqlSession이 실제 SQL 실행을 담당합니다.

호출 흐름 다이어그램 — Service → MapperProxy → MapperMethod → SqlSession

sequenceDiagram participant Service participant Proxy as MapperProxy participant Method as MapperMethod participant Session as SqlSession Service->>Proxy: mapper.selectOne(...) Proxy->>Method: execute(sqlSession, args) Method->>Session: selectOne(statement, param)

핵심 코드 — invoke()가 호출을 가로채 execute(sqlSession, args)로 넘긴다

// MapperProxy.java
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
// MapperMethod.java
public Object execute(SqlSession sqlSession, Object[] args) {
    Object param = method.convertArgsToSqlCommandParam(args);
    Object result = sqlSession.selectOne(command.getName(), param);
    return result;
}

코드 해설 — MyBatis는 구현체 대신 인터페이스를 프록시로 감싼다

MyBatis는 Repository 구현체를 제공하는 대신, Mapper 인터페이스를 프록시로 감쌉니다. 그래서 서비스는 인터페이스 메서드를 호출하지만 실제로는 MapperProxy가 SQL 세션으로 위임합니다.


설계 의도 — SQL은 개발자가 쓰되 호출부에서는 일반 인터페이스 메서드로 보이게 한다

개발자는 SQL에 집중하면서도, 호출부에서는 일반 인터페이스 메서드처럼 사용할 수 있게 하기 위한 구조입니다. 즉 SQL 매퍼 패턴과 자바 인터페이스 호출 경험을 동시에 만족시키려는 설계입니다.


다음 단계 연결 — 15-M2 SqlSession이 DB 쿼리 실행으로 내려가는 과정으로 이어진다

다음 문서 15-M2에서는 SqlSession이 실제 DB 쿼리 실행으로 어떻게 내려가는지 봅니다.

← 이전: 15-J6. JpaRepository → Service | 다음: 15-M2. Mapper → DB