5장. 엔티티 리스너들과 콜백 메소드들

양석 메커니즘 내부에서 발생하는 어떤 이벤트들에 반응하는 것은 어플리케이션에 자주 유용하다. 이것은 어떤 종류의 일반적 기능, 그리고 미리 만들어진 기능의 확장에 대한 구현을 허용해준다. EJB3 명세서는 이 용도를 위한 두 개의 관련된 메커니즘들을 제공한다.

엔티티의 메소드는 하나의 특정한 엔티티 생명 주기 이벤트의 통보를 수신받기 위한 하나의 콜백 메소드로서 고안될 수 있다. 당신은 또한 엔티티 클래스 내부에 직접 정의된 콜백 메소드들 대신에 사용될 하나의 엔티티 리스너 클래스를 정의할 수 있다. 하나의 엔티티 리스너는 아규먼트 없는 생성자를 가진 상태없는 클래스이다. 엔티티 리스너는 엔티티 클래스를 @EntityListener 주해로 엔티티 클래스를 주해함으로써 정의된다:

@Entity(access=FIELD) 
@EntityListener(class=Audit.class)
public class Cat {
    @Id private Integer id;
    private String name;
    private Calendar dateOfBirth;
    @Transient private int age;
    private Date lastUpdate;
    //getters and setters

    /**
     * Set my transient property at load time based on a calculation,
     * note that a native Hibernate formula mapping is better for this purpose.
     */
    @PostLoad
    public void calculateAge() {
        Calendar birth = new GregorianCalendar();
        birth.setTime(dateOfBirth);
        Calendar now = new GregorianCalendar();
        now.setTime( new Date() );
        int adjust = 0;
        if ( now.get(Calendar.DAY_OF_YEAR) - birth.get(Calendar.DAY_OF_YEAR) < 0) {
            adjust = -1;
        }
        age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR) + adjust;
    }
}

public class LastUpdateListener {
    /**
     * automatic property set before any database persistence
     */
    @PreUpdate
    @PrePersist
    public void setLastUpdate(Cat o) {
        o.setLastUpdate( new Date() );
    }
}

동일한 콜백 메소드 또는 엔티티 리스너 메소드는 하나 이상의 콜백 주해들로서 주해될 수 있다. 주어진 하나의 엔티티에 대해, 당신은 그것이 하나의 콜백 메소드이든지 하나의 엔티티 리스너 메소드이든지 간에 동일한 콜백 주해에 의해 주해되는 두 개의 메소드들을 가질 수 없다. 하나의 콜백 메소드는 반환 타입 없이 어떤 임의의 이름을 가진 하나의 아규먼트 없는 메소드이다. 하나의 엔티티 리스너는 시그너처 public void <METHOD>(Object)을 가지며 여기서 Object는 실제 엔티티 타입이다 (Hibernate 엔티티 관리자는 이 생성자를 완화시키고 (몇몇 엔티티들을 가로질러 리스너들을 공유하는 것을 허용하는) java.lang.Object 타입의 Object를 허용함을 노트하라.)

하나의 콜백 메소드는 RuntimeException을 일으킨다. 아무튼 현재 트랜잭션은 롤백되어야 한다. 다음 콜백들이 정의된다:

표 5.1. Callbacks

타입설명
@PrePersist엔티티 관리자 persist 연산이 실제로 실행되거나 케스케이드 되기 전에 실행된다. 이 호출은 persist 연산과 동기적이다.
@PreRemove엔티티 관리자 remove 연산이 실제로 실행되거나 케스케이드 되기 전에 실행된다. 이 호출은 remove 연산과 동기적이다.
@PostPersist엔티티 관리자 persist 연산이 실제로 실행되거나 케스케이드 된 후에 실행된다. 이 호출은 데이터베이스 INSERT가 실행된 후에 호출된다.
@PostRemove엔티티 관리자 remove 연산이 실제로 실행되거나 케스케이드 된 후에 실행된다. 이 호출은 remove 연산과 동기적이다.
@PreUpdate데이터베이스 UPDATE 연산 전에 실행된다.
@PostUpdate데이터베이스 UPDATE 연산 후에 실행된다.
@PostLoad하나의 엔티티가 현재의 영속 컨텍스트 속으로 로드된 후에 또는 하나의 엔티티가 갱신된 후에 실행된다.

하나의 콜백 메소드는 EntityManager 메소드나 Query 메소드를 호출하지 말아야 한다!