✔ 리스너

모든 엔티티를 대상으로 언제 어떤 사용자가 삭제를 요청했는지 모두 로그로 남겨야 하는 요구사항이 있다면, 애플리케이션 삭제 로직을 하나씩 찾아 로그를 남기는 것은 비효율적이다.

JPA 리스너 기능을 사용하면 엔티티의 생명주기에 따른 이벤트를 처리할 수 있다.

1. 이벤트 종류

리스너 시점

No 리스너 설명
1 PostLoad 엔티티가 영속성 컨텍스트에 조회된 직후 또는 refresh를 호출한 후 (2차 캐시에 저장되어 있어도 호출됨)
2 PrePersist persist()를 호출해서 엔티티를 영속성 컨텍스트에 관리하가 직전에 호출된다.식별자 생성 전략을 사용한 경우 엔티티에 식별자는 아직 존재하지 않는다. 새로운 인스턴스를 merge할 때도 수행된다.
3 PreUpdate flushcommit를 호출해서 엔티티를 DB에 수정하기 직전에 호출된다.
4 PreRemove remove()를 호출해서 엔티티를 영속성 컨텍스트에서 삭제하기 직전에 호출된다. 또한 삭제 명령어로 영속성 전이가 일어날 때도 호출된다.orphanRemoval에 대해서는 flushcommit 시에 호출
5 PostPersist flushcommit를 호출해서 엔티티를 DB에 저장한 직후에 호출된다. 식별자가 항상 존재한다.식별자 생성 전략이 IDENTITY면 식별자를 생성하기 위해 persist()를 호출하면서 DB에 해당 엔티티를 저장하므로 이때는 persist()를 호출한 직후에 바로 PostPersist가 호출된다.
6 PostUpdate flushcommit를 호출해서 엔티티를 DB에 수정한 직후에 호출된다.
7 PostRemove flushcommit를 호출해서 엔티티를 DB에 삭제한 직후에 호출된다.

2. 이벤트 적용 위치

이벤트는 엔티티에서 직접 받거나 별도의 리스너를 등록해서 받을 수 있다. - 엔티티에 직접 적용 - 별도의 리스너 등록 - 기본 리스너 사용

엔티티에 직접 적용

@Entitypublic class Duck{    @Id @GeneratedValue    public Long id;    private String name;    @PrePersist    public void prePersist(){        System.out.println("Duck.prePersist id = " + id);    }    @PrePersist    public void postPersist(){        System.out.println("Duck.postPersist id = " + id);    }    @PrePersist    public void postLoad(){        System.out.println("Duck.postLoad id = " + id);    }    @PrePersist    public void preRemove(){        System.out.println("Duck.preRemove id = " + id);    }    @PrePersist    public void postRemove(){        System.out.println("Duck.postRemove id = " + id);    }}/*출력Duck.prePersist id = null //아이디가 생성되기 전에 호출Duck.prePersist id = 1    //아이디가 생성된 후에 호출

별도의 리스너 등록

@Entity@EntityListeners(DuckListener.class)public class Duck{    ...}public class DuckListener{    //특정 타입이 확실하면 특정 타입을 받을 수 있다.    @PrePersist    private void prePersist(Object obj){        System.out.println("DuckListener.prePersist obj = ["+ obj +"]");    }    //특정 타입이 확실하면 특정 타입을 받을 수 있다.    @PostPersist    private void postPersist(Object obj){        System.out.println("DuckListener.postPersist obj = ["+ obj +"]");    }}

리스너는 대상 엔티티를 파라미터로 받을 수 있다. 반환 타입은 void로 설정해야 한다.

기본 리스너 사용

모든 엔티티의 이벤트를 처리하려면 META-INF/orm.xml에 기본 리스너로 등록하면 된다.

<?xml version="1.0" encoding="UTF-8"?><entity-mappings ...>    <persistence-unit-metadata>        <persistence-unit-defaults>            <entity-listeners>                <entity-listener class="org.tmkim.jpashop.domain.test.listener.DefaultListener" />            </entity-listeners>        </persistence-unit-defaults>    </persistence-unit-metadata></entity-mappings>

리스너를 여러 개 등록했을 떄 이벤트 호출 순서 1. 기본 리스너 2. 부모 클래스 리스너 3. 리스너 4. 엔티티

더 세밀한 설정