SpringDataJpa源码理解

上一篇讲解了SpringDataJpa的基本使用,下面简单说一下源码
我们以其中的一个test为案例进行分析:

 

我们可以发现resumeDao它是一个代理对象,类型是SimpleJpaRepository,是由JdkDynamicAopProxy产生的。

断点分析SimpleJpaRepository产生过程;

我们可以借鉴spring源码解读过程,通过AbstractApplicationContext的refresh方法查找细节;

进入断点查找线索

我们查找到beanName为resumeDao,点击下一步时发现他是 FactoryBean,并且 FactoryBean的类型是 JpaRepositoryFactoryBean;

读过spring源码的人都知道,factoryBean里面是有个getObject方法,它会产生一个具体的对象;

为什么会给它指定为 JpaRepositoryFactoryBean 呢?并且指定这个 FactoryBean 是在什么时候发生的呢?

我们着重分析一下是如何传入一个 resumeDao 就返回一个已经指定 classJpaRepositoryFactoryBeanBeanDefinition 对象的

上图 getMerGedLocalBeanDefinition 就有了,断点进入查看详情

我们可以看到是从map中获取的,那我们就看一下是什么时候put进去的;

此时定位到了一个方法在做这件事

观察这个方法的调用栈

我们发先 getMerGedLocalBeanDefinition 方法调用时 参数传进来的时候,这个BeanDefinition的class类型就已经被指定为 JpaRepositoryFactoryBean 了。我们需要观察该方法的调用栈;

回溯发现是在这一步通过beanName获取到了一个 Beandefinition,该 Beandefinition中的class是被指定为FactoryBean了;

我们在return处打断点重新走一遍,进入 getBeanDefinition 方法;

所有的bean被扫描处理之后,都进行注册,注册到该map中;

找到beanDefinitionMap.put关联方法,发现都在 registerBeanDefinition 中,向BeanDefinition中注入;

断点执行如下

发现传进来的时候就已经指定为 JpaRepositoryFactoryBean 了,继续回溯

解析jpa:respository标签过程,注意,这一步很重要!

进入该方法,

重点追踪该方法,BeanDefinition中class指定就发生在这里,我们debug进去该方法;

这一步执行之后,JpaRepositoryFactoryBean 就产生了,,,

debug进去rootBeanDefinition方法中

我们发现这个方法返回了一个固定的class类型,就叫做 JpaRepositoryFactoryBean;

通过上述追踪我们发现,其实在applicationContext.xml文件中,如下

<jpa:repositories base-package="com.yun.demo.dao" entity-manager-factory-ref="entityManagerFactory"
                  transaction-manager-ref="transactionManager"/>

扫描到的接口,在进行BeanDefinition注册的时候,class会被固定的指定为 JpaRepositoryFactoryBean


追踪完JpaRepositoryFactoryBean,我们可以拓展一下 JpaRepositoryFactoryBean 是一个什么样的类;

我们重点关注一下factoryBean里面的getObject方法;

JpaRepositoryFactoryBean 爷爷类 RepositoryFactoryBeanSupport 中找到了getObject方法;

getObject方法里面我们查看一下this.repository.get()是如何赋值的;

JpaRepositoryFactoryBean 的爷爷类中初始化方法完成了对 repository 变量的赋值;repository 这个变量里面持有了我们需要的对象,而且这个对象它是一个代理对象

研究过过spring bean生命周期的应该知道,afterPropertiesSet 方法是初始化之后调用的方法,如下,实现了InitializingBean接口,

在return处打上断点,我们进去,查看是是如何产生代理对象并且赋值的,

如上图 information生成这一步,指定了要产生的代理对象类型是SimpleJpaRepository;

重新debug进入标记的方法,看看它是怎么指定的;

上图操作,baseClass该类型就是SimpleJpaRepository,直接进入该方法查看详情;

搞了半天,代理对象类型固定为了 SimpleJpaRepository(和 JpaRepositoryFactoryBean 获取方式一样)

要借助代理对象工厂产生代理对象

获取代理对象

选择使用JDK动态代理!

我们看一下JdkDynamicAopProxy结构

类中有一个方法可以产生代理对象,而增强的也正是自己,说明当前类应该是实现了InvocationHandler接口,当前类中应该也有一个Invoke方法;

如图!由此可见,JDK动态代理会生成一个类型为 SimpleJpaRepository 的代理对象,而该对象的增强逻辑就在 JdkDynamicAopProxy类的Invoke方法中.

我点击 SimpleJpaRepository 发现一个好玩的事情,如下图

原来,SimpleJpaRepository类实现了 JpaRepository 接口和 JpaSpecificationExecutor 接口

呕吼,找到根了,方法实现调用了jpa原本的api;