上一篇讲解了SpringDataJpa的基本使用,下面简单说一下源码
我们以其中的一个test为案例进行分析:
我们可以发现resumeDao它是一个代理对象,类型是SimpleJpaRepository,是由JdkDynamicAopProxy产生的。
断点分析SimpleJpaRepository产生过程;
我们可以借鉴spring源码解读过程,通过AbstractApplicationContext的refresh方法查找细节;
我们查找到beanName为resumeDao,点击下一步时发现他是 FactoryBean,并且 FactoryBean的类型是 JpaRepositoryFactoryBean;
读过spring源码的人都知道,factoryBean里面是有个getObject方法,它会产生一个具体的对象;
为什么会给它指定为 JpaRepositoryFactoryBean 呢?并且指定这个 FactoryBean 是在什么时候发生的呢?
我们着重分析一下是如何传入一个 resumeDao 就返回一个已经指定 class 为 JpaRepositoryFactoryBean 的 BeanDefinition 对象的
上图 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 接口