EntityManager에서 getReference()를 사용하여 진짜 객체를 참조하여 가짜 객체를 만든다.
진짜 객체를 호출할 때는 em.find()를 사용하지만, 가짜 객체는 em.getReference()를 사용한다.

엔티티를 처음 조회할 때 실제 데이터베이스 조회를 지연하고, 필요한 시점에 데이터베이스에서 데이터를 조회한다.
프록시 객체는 원래 엔티티 클래스를 상속받아 만들어지며, 실제 데이터 조회 시점에 데이터베이스에 접근한다.
LazyInitailizationException발생가능하다.Member member = em.getReference(Member.class, "id1");
member.getName(); //프록시 초기화
(1) em.getReference()로 프록시 객체를 생성하여 getName()을 쓰면 초기화 과정이 시작된다.
(2) MemberProxy 객체에 Member target 값이 존재하지 않아서 JPA가 영속성 컨텍스트에 값을 받아오는 초기화 요청을 한
(3) 영속성 컨텍스트가 DB에서 조회하여 값을 받아온다.
(4) 실제 영속성 컨텍스트가 실제 Entity를 생성해준다.
(5) 실제 객체는 이제 값을 제대로 가지고 있기 때문에 Member target의 getName()을 호출해서 영속성 컨텍스트가 호출한 값을 가져올 수 있다.
(6) 프록시 객체에 target이 할당되면, 프록시 객체의 초기화 동작은 없어도 된다.
프록시객체는 실제 엔티티 클래스를 상속받기 때문에 타입캐스팅에 주의해야한다.
try {
Member member1 = new Member();
member1.setUserName("member1");
em.persist(member1);
em.flush();
em.clear();
Member refMember = em.getReference(Member.class, member1.getId());
Member member = em.find(Member.class, member1.getId());
System.out.println("refMember = " + refMember.getClass());
System.out.println("refMember == member : " + (refMember == member));
// A instanceof B: A 객체가 B를 상속받았는지 확인하는 메서드, boolean type 으로 true와 false를 return 한다.
System.out.println("refMember instanceOf member : " + (refMember instanceof Member));
}
프록시가 원본 클래스의 객체를 상속받았는지 확인해보면 true가 나온다.