반응형

회사 코드에 EntityManager를 사용하여 try~catch~finally를 사용하여 finally에서 해당 EntityManager 인스턴스를 close()하고 자원을 반납하고 있었습니다. 

하지만 이펙티브 자바에서는 [아이템 9. try-finally 대신 try-with-resources를 사용하라.] 라는 내용이 존재합니다. 

그래서 EntityManager를 try-with-resources로 리팩터링을 하려고 했지만, AutoClosable이 지원하지 않는다고 IDE에서 말해주고 있었습니다. 관련 글을 찾던 중 블로그에 해당 이슈는 오픈소스에 fix issue로 등록이 되어 있고 특정 버전 이후에 추가가 되었다고 합니다.

제가 회사에서 쓰는 java persistence-api 라이브러리는 2.x로 AutoClosable을 지원하지 않았고, 3.x대로 올라가면서 Jakarta Persistence API -> 3.1.0 지원하게 된것을 알게되었습니다.

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default");
try(EntityManager entityManager = entityManagerFactory.createEntityManager()){

}

 

package jakarta.persistence;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Metamodel;
import java.util.List;
import java.util.Map;

public interface EntityManager extends AutoCloseable {
    void persist(Object var1);

    <T> T merge(T var1);

    void remove(Object var1);

해당 Jakarta Persistence API의 EntityManager 인터페이스를 보면 알 수 있듯이 해당 클래스는 AutoCloseable을 상속하고 있는 것을 알 수 있습니다.

public interface AutoCloseable {
    /**
     * Closes this resource, relinquishing any underlying resources.
     * This method is invoked automatically on objects managed by the
     * {@code try}-with-resources statement.
     *
     * <p>While this interface method is declared to throw {@code
     * Exception}, implementers are <em>strongly</em> encouraged to
     * declare concrete implementations of the {@code close} method to
     * throw more specific exceptions, or to throw no exception at all
     * if the close operation cannot fail.
     *
     * <p> Cases where the close operation may fail require careful
     * attention by implementers. It is strongly advised to relinquish
     * the underlying resources and to internally <em>mark</em> the
     * resource as closed, prior to throwing the exception. The {@code
     * close} method is unlikely to be invoked more than once and so
     * this ensures that the resources are released in a timely manner.
     * Furthermore it reduces problems that could arise when the resource
     * wraps, or is wrapped, by another resource.
     *
     * <p><em>Implementers of this interface are also strongly advised
     * to not have the {@code close} method throw {@link
     * InterruptedException}.</em>
     *
     * This exception interacts with a thread's interrupted status,
     * and runtime misbehavior is likely to occur if an {@code
     * InterruptedException} is {@linkplain Throwable#addSuppressed
     * suppressed}.
     *
     * More generally, if it would cause problems for an
     * exception to be suppressed, the {@code AutoCloseable.close}
     * method should not throw it.
     *
     * <p>Note that unlike the {@link java.io.Closeable#close close}
     * method of {@link java.io.Closeable}, this {@code close} method
     * is <em>not</em> required to be idempotent.  In other words,
     * calling this {@code close} method more than once may have some
     * visible side effect, unlike {@code Closeable.close} which is
     * required to have no effect if called more than once.
     *
     * However, implementers of this interface are strongly encouraged
     * to make their {@code close} methods idempotent.
     *
     * @throws Exception if this resource cannot be closed
     */
    void close() throws Exception;
}

 

https://k3068.tistory.com/98

 

왜? EntityManager는 AutoCloseable 구현하고 있지 않은가?

EntityManager는 쓰레드 간에 공유를 하지 않고 사용 후 바로 정리해야 한다고 한다. public void run(ApplicationArguments args) throws Exception { EntityManager em = entityManagerFactory.createEntityManager(); EntityTransaction transa

k3068.tistory.com

 

https://www.inflearn.com/questions/231224/entitymanager-%EB%8A%94-%EC%99%9C-autocloseable-%EC%9D%84-%EC%A7%80%EC%9B%90%ED%95%98%EC%A7%80-%EC%95%8A%EB%82%98%EC%9A%94

 

EntityManager 는 왜 AutoCloseable 을 지원하지 않나요? - 인프런 | 질문 & 답변

안녕하세요문득 궁금한점이 생겨서 질문해봅니다.항상 사용하고 버려야 한다면 AutoCloseable지원하여 try-with-resource 문을 사용할 수 있도록 도움을 주면 좋을 것 같다고 생각이 들었지만시용해볼

www.inflearn.com

 

728x90
반응형

정적 메서드와 정적 필드만을 담은 클래스

1) java.lang,Math, java.util.Arrays과 같이 기본 타입 값이나 배열 관련 메서드들을 모아놓음
2) java.util.Collections처럼 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드를 모아놓을 수 있음
3) final 클래스와 관련된 메서드들

추상 클래스로 만드는 것으로는 인스턴스화를 막을 수 없다.

private 생성자를 추가하면 클래스의 인스턴스활르 막을 수 있음

인스턴스를 만들 수 없는 유틸리티 클래스

public class UtilityClass {

    //기본 생성자가 만들어지는 것을 막는다(인스턴스화 방지용)
    private UtilityClass(){
        throw new AssertionError();
    }
}
  • 위 코드는 어떤 환경에서도 클래스가 인스턴스화되는 것을 막아줌
  • 상속을 불가능하게 하는 효과도 존재함
  • 하위 클래스가 상위 클래스의 생성자에 접근할 길이 막힘
728x90
반응형

싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말함

클래스를 싱글턴으로 만들면 이를 사용하는 클라이언튼를 테스트하기가 어려워 질 수 있음
타입이 인터페이스이면 그 인터페이스를 구현해서 만든 싱글턴이 아니라면 싱글턴 인스턴스를 가자 구현으로 대체할 수 없음

public static final 필드 방식의 싱글턴

public class Elvis{
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }

    public void leaveTheBuilding() { ... }
}

위와 같은 방식으 싱글턴 생성은 리플렉션 API를 사용할 경우 싱글톤임을 보장하지 못함
이러한 공격(?)을 방어하려면 생성자를 수정하여 두 번째 객체가 생성되려 할 때 예외를 던지게 하면됨

장점

1) 해당 클래스가 싱글텀임이 API에 명백히 드러남, public static 필드가 final이니 절대로 다른 객체를 참조할 수 없음
2) 간결함

정적 팩터리 방식의 싱글턴

public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() {return INSTANCE;}

    public void leaveTheBuilding() { ... }
}

Elvis.getInstance는 리플렉션을 통한 예외에서도 제2의 Elvis 인스턴스를 만들지 않음

장점

1) API를 바꾸지 않고도 싱글턴이 아니게 변경 할 수 있다. -> 스레드별 다른 인스턴스
2) 정적 팩터리를 제네릭 싱글턴 팩터리로 만들 수 있음
3) 원한다면 정적 팩터리의 메서드 참조를 공급자로 사용할 수 있음

싱글톤 클래스를 직렬화하는 경우

  • 모든 인스턴스 필드를 일시적이라고 선언하고, readResolve 메서드를 제공해야함
  • 이렇게 하지 않으면 인스턴스를 역직렬화할 때마다 새로운 인스턴스가 만들어짐
  • 싱글턴임을 보장해주는 readResolve 메서드
  • private Object readResolve(){ return INSTANCE; }

열거 타입 방식의 싱글턴 - 바람직한 방법

public enum Elvis {
    INSTANCE; 

    public void leaveTheBuilding(){ ... }
}
  • 복잡한 직렬화 상황이나 리플렉션 공경에서도 제2의 인스턴스가 생기는 일을 완벽히 막아줌
  • 대부분 상황에서 원소가 하나뿐인 열거 타입이 싱글턴을 만드는 가장 좋은 방법임
728x90

+ Recent posts