작성
·
1.3K
5
13:43 부분을 보면 JPA 는 내부적으로 리플렉션을 통해서 객체를 생성하기 때문에 기본 생성자가 필요하다고 하셨는데요.
다음과 같이 기본 생성자는 생성하지 않고 코드를 돌리더라도
문제없이 돌아가던데,
내부적으로 기본생성자가 없더라도 동작하도록 변경이 된걸까요.?
추가)
추가적으로 강의를 진행 하던 중에 em.find() 로 실행하니 이제는 디폴트 메소드가 없다고 에러메시지가 출력이 되네요.
persist() 할 때는 출력되지 않던 에러가 find() 에서는 출력되는데 어떤 메커니즘 차이 때문에 이런 결과가 발생하는 건가요.?
답변 6
9
안녕하세요.
어떤 부분이 궁금하신지 이해했습니다^^
여기는 좀 더 깊이있는 내용이 필요한데요.
자바는 ServiceLoader라는 기능을 제공합니다. 이것을 통해서 라이브러리에 있는 특정 인터페이스의 구현 클래스를 동적으로 찾아낼 수 있습니다.
JPA는 자바가 제공하는 ServiceLoader라는 기능을 사용해서 JPA의 실제 구현 객체를 찾아내고 동작시킵니다.
JPA는 PersistenceProvider 인터페이스를 제공하는데요.
하이버네이트는 HibernatePersistenceProvider라는 PersistenceProvider 인터페이스를 구현한 클래스를 라이브러리안에서 제공합니다.
그래서 Persistence.createEntityManagerFactory(..) 메서드에 궁금해하시는 비밀이 숨겨져 있습니다.
(JPA 중에서 인터페이스가 아니라 자바 코드가 제공되는 부분입니다.)
코드를 잘 찾아가면 다음 부분이 호출됩니다.
DefaultPersistenceProviderResolver.getPersistenceProviders();
그리고 ServiceLoader를 통해서 PersistenceProvider 구현체를 찾는 로직이 있습니다.
Iterator<PersistenceProvider> ipp = ServiceLoader.load(PersistenceProvider.class, loader).iterator();
여기서 결과로 HibernatePersistenceProvider가 찾아지는 것이지요.
더 자세한 내용은 자바 ServiceLoader로 검색해보시면 원하는 결과를 찾으실 수 있을거에요^^
도움이 되셨길 바래요^^
1
1
네 추가 설명드리겠습니다.
JPA는 인터페이스라고 이해하시면 됩니다. 그 인터페이스를 하이버네이트가 구현한 것이지요.
JPA 스펙은 하이버네이트 뿐만 아니라 여러 회사들이 구현할 수 있습니다. 그중에 하이버네이트도 하나인 것이지요.
JPA 스펙에서 기본생성자가 필수로 강제해두었기 때문에, 이런 부분은 따르는 것이 좋습니다. 그렇지 않으면 향후 하이버네이트도 버전업 변경되면서 이런 부분에 문제가 발생할 수 있고, 혹시 하이버네이트를 다른 구현체 라이브러리로 변경하면 동작하지 않을 수도 있습니다.
다시 돌아가서
JPA는 인터페이스 입니다. 지금 보시는 코드들은 모두 인터페이스고 실제 그 하부에서 구현 객체들은 모두 하이버네이트 구현 객체로 동작합니다. 그래서 JPA는 껍데기일 뿐이므로 사실 JPA를 통해 실행되는 것은 사실 없습니다.
EntityManager도 잘 보시면 인터페이스고, EntityManagerFactory도 인터페이스 입니다.
처음 Persistence.createEntityManagerFactory를 호출하시면, 그 내부에서 EntityManagerFactory의 하이버네이트 구현체인 SessionFactory를 반환합니다. 여기서부터 모든 것이 시작되는 것이지요.
우리눈에는 EntityManagerFactory라고 보이지만, 실제는 런타임에 동적으로 구현 클래스가 들어가는 것입니다.
이 EntityManagerFactory.createEntityManger()를 호출하면 실제는 SessionFactory.createEntityManager()가 다형성에 의해서 호출됩니다. 그러면 여기서는 EntityManger 인터페이스의 하이버네이트 구현체인 Session이라는 것이 반환됩니다.
그런데 만약 하이버네이트가 아닌 EclipseLink같은 다른 라이브러리를 사용하신다면 해당 라이브러리의 구현제가 제공되겠지요.
이렇게 코드상에 하이버네이트가 전혀 들어나지 않도록 하는 것이 바로 인터페이스 설계의 기본입니다. 그런면에서 JPA는 매우 잘 설계된 인터페이스라 할수 있습니다. 향후 하이버네이트를 다른 구현 라이브러리도 변경해도 코드를 거의 고치지 않아도 되니까요^^
도움이 되셨길 바래요.
1
안녕하세요. 햇병아리님
JPA의 기본 스펙은 엔티티에 기본 생성자가 필수로 있어야 합니다. 그런데 하이버네이트 같은 구현체 들은 조금 더 유연하게 바이트코드를 조작하는 라이브러리등을 통해서 이런 문제를 회피합니다. 하지만 이런 것은 완벽한 해결책이 아니므로, 상황에 따라 될 때도 있고 되지 않을 때도 있습니다. 따라서 JPA 스펙에서 가이드한 것 처럼 기본생성자를 꼭 넣어주세요.
감사합니다.
0
오늘도 늦은 밤 선생님 답변에 무릅을 탁 치고 갑니다.
친절한 답변 감사드립니다.
위에 설명에 런타임에 동적으로 구현 클래스가 들어간다고 했는데, 혹시 이 부분은 JPA가 persistence.xml 설정파일 내부에
"hibernate.dialect" 이 부분을 보고 "아 하이버네이트를 사용해야 겠다." 라고 판단하고 하이버네이트를 사용하는 것인가요.?
스프링 같은 경우도 동적으로 런타임 변경할 때 xml 이나 config 파일을 보고 의존성을 주입 해주는 형태로 동적으로 변경하는
것으로 알고 있는데,
JPA가 동적으로 변경한다고 한다면 단순히 라이브러리만 보고 판단하는것은 아닌것 같고 스프링 처럼 무언가를 보고 변경을 할텐데,
마땅히 의심할만한 대상이 persistence.xml 밖에 없어서요.
0
선생님 추가적으로 문의 드립니다.
JPA 의 기본 스펙은 엔티티 기본 생성자가 필수로 있어야 한다고 했는데,
저희가 실습하는 코드를 보면 entityManagerFactory, entityManager, persistence 모두 javax.persistence 패키지에 포함되어 있는 것들이고, 제가 알고 있기로는 javax.persistence 모두 JPA 기술인 것으로 알고 있는데,
위의 코드에서 하이버네이트를 동작하게 하는 부분이 있는 건가요.?
아니면 javax.persistence 패키지에 정의되어 있는 entityManager 나 entityManagerFactory 내부에
가지고 있는 라이브러리 중에 하이버네이트가 있으면 하이버네이트 동작하게 끔 하는 코드가 있는 건가요.?
만일 JPA 로만 동작하고 있다면, 선생님이 말씀 해주신 JPA 는 스펙상 기본 생성자가 필수로 있어야 한다.
하는 부분이 이해가 잘 되지 않습니다.......
혹 제가 잘못 알고 있거나 이해하고 있는 부분이 있다면 설명 부탁 드립니다....