JPA的Repository操作數(shù)據(jù)庫原理

在了解JPA的Repository原理之前,先了解一下EntityManager的應用,通過它可以開啟一個事務,從而令之后的操作在保持在事務中。

public class JpaTest {

    EntityManagerFactory factory;

    @Before
    public void before() {
        // 從META-INF的persistence.xml獲取持久化單元
        factory = Persistence.createEntityManagerFactory("hibernateJPA");
    }

    // 立即查詢
    @Test
    public void testR() {
        EntityManager em = factory.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        Customer customer = em.find(Customer.class, 1L);
        System.out.println("========================");
        System.out.println(customer);
        tx.commit();
    }
}

以Hibernate實現(xiàn)的JPA為例,通過JDK提供的動態(tài)代理機制,生成JPA的Repository接口的實現(xiàn)類,從如下的單元測試作為切入點,我們可以進一步跟蹤JPA生成的動態(tài)代理是如何進行數(shù)據(jù)庫操作的

@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringdataJpaTest {

    // jdk動態(tài)代理的實例
    @Autowired
    CustomerRepository repository;

    @Test
    public void testR() {
        Optional<Customer> byId = repository.findById(20L);
        System.out.println(byId.orElse(null));
    }
}

通過斷點,可以看到注入的CustomerRepository是一個動態(tài)代理對象$Proxy,創(chuàng)建動態(tài)代理所需的接口InvocationHandler實現(xiàn)類采用org.springframework.aop.framework.JdkDynamicAopProxy

動態(tài)代理類細節(jié)

進一步通過斷點到JdkDynamicAopProxy類中,這是Spring提供的一個用于生成動態(tài)代理對象的工廠類,可以看到這個類中存在獲取具體代理對象的方法,同時生成的動態(tài)代理對象調(diào)用目標方法的時候,也會相應的觸發(fā)這個類中的攔截方法invoke,相關(guān)的代碼如下:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    // ...

    // 通過如下兩個方法可以獲取到當前類需要創(chuàng)建的代理對象
    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
    }

    // ...

    // 當代理對象觸發(fā)方法的調(diào)用時,會進入到這個方法,Spring在這里會構(gòu)成一個調(diào)用鏈,
    // 并通過遞歸的方式,不斷地觸發(fā)調(diào)用鏈上的每一個方法
    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // ...

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        if (chain.isEmpty()) {
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        } else {
                MethodInvocation invocation =
                        new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                retVal = invocation.proceed();
        }

        // ...
    }
}

仔細觀察JdkDynamicAopProxy類中的targetSource屬性,內(nèi)部封裝了org.springframework.data.jpa.repository.support.SimpleJpaRepository類,這是spring-data-jpa提供的通用Repository,類似上文舉過的單元測試例子,它內(nèi)部封裝了EntityManager,通過后者就能夠獲取到當前項目中實現(xiàn)了JPA規(guī)范的Hibernate的SessionImpl對象,從而完成數(shù)據(jù)庫操作,SimpleJpaRepository類如下:

@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {

    // ...

    @Override
    public Optional<T> findById(ID id) {
        Assert.notNull(id, ID_MUST_NOT_BE_NULL);
        Class<T> domainType = getDomainClass();
        if (metadata == null) {
                return Optional.ofNullable(em.find(domainType, id));
        }
        LockModeType type = metadata.getLockModeType();
        Map<String, Object> hints = new HashMap<>();
        getQueryHints().withFetchGraphs(em).forEach(hints::put);
        return Optional.ofNullable(type == null ? em.find(domainType, id, hints) 
                                                : em.find(domainType, id, type, hints));
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容