spring-data-jpa初步学习.

这篇博客是我自己学习spring-data-jpa时的一些理解,可能有错误.还希望看到的大牛能指正.

本博客深度不够,只是简单的一些自我的理解,还望轻喷.

 

    为什么突然对spring-data-jpa(下面简称JPA)感兴趣,要说到一次我自己写的一个针对hbase数据库的增删查改的工具类.里面使用的是泛型的方式(博客链接),因为对hbase中操作表,很多方法都是可以复用的,当时第一时间想到的就是泛型,但现在回想一下,其他(hibernate,JPA等)是如何来实现的呢?因为在使用的工程中,自定义的持久层都是继承的HibernateDaoSupport或JpaRepository就能实现数据的持久层了(JPA还会有一些通用的方法),所以当时就萌生了一个念头,想去看看他们是如何实现的.

   先看了hibernate的实现,其实我自己写的工具类也借鉴了一下hibernate,先定义一个实现类,继承HibernateDaoSupport,实现自定义方法.查看上面的博客链接里面就可以看出来,

自定义daoImpl层, 实现自定义接口dao

​
class daoImpl<T> implements dao<T> {
    private Class<T> type;
 
    @SuppressWarnings("unchecked")
    public Test2() {
      //getClass().getGenericSuperclass() 得到 当前对象的直接超类的 Type
      ParameterizedType parameterizedType = (ParameterizedType) getClass()
          .getGenericSuperclass();
      this.type = (Class<T>) parameterizedType.getActualTypeArguments()[0];
      System.out.println(getClass().getGenericSuperclass());
    }
  }

​

在实现类中保存泛型的实际类型(type),以便在方法中能使用.然后接口中添加通用的方法.以后需要用到时,就在根据具体的实体对象来实现各自的dao层

​
class myDao extends daoImpl<Entity> {
    
}

​

想这样,myDao中就会有daoImpl中的具体方法了(通用方法)

hibernate的研究没有太过深入,比如如何从数据库中获取数据后组装成具体对象这块就没有去看,毕竟当时只关注了如何让一个实现类通用这个问题上了.

     再来看看JPA,JPA非常强大,现在才使用了它的一点点功能就能看出来里面的强大.可以使用@Query来写JPQL语句查询,也可以写原生的sql查询,还能通过方法名来查询(findByName()这样直接写一个方法,就可以通过实体对象中name属性来查找)是不是很牛逼.而我这次兴趣点在于为什么我们一个实体对象的Respository继承JpaRepository,JpaSpecificationExecutor这两个类后,就能使用很多方法了,如findOne(),save(Entity entity)等,甚至我们都没有对自己的Respository接口写实现类就能做到基本的增删改查等操作,这些东西是谁帮我们做了呢?接下来,就是探索JPA的旅程了.

    在使用JPA时,我们只需要这样既可

​
@Repository("myRepository")
public interface myRepository
    extends
      JpaRepository<myEntity, String>,
      JpaSpecificationExecutor<myEntity> {


      @Query
      public void function();
}

​

    然后就可以使用myRepository来进行一系列数据操作了,为什么我们都没有实现myRepository接口,但我们还是可以调用find,save等方法呢?这个就要看JPA源码了.

我们发现JpaRepository类有一个实现类SimpleJpaRepository,而SimpleJpaRepository就是我们上面能用到的find,save,delete等方法的实现.那我们的自定义myRepository,是如何调用到SimpleJpaRepository里面的实现方法的呢?

其实查看JPA源码能发现org.springframework.data.jpa.repository.support.JpaRepositoryFactory是JPARepository的创建工厂类,spring在加载时,其实都是通过JpaRepositoryFactory下的

    @Override
	protected Object getTargetRepository(RepositoryInformation information) {

		SimpleJpaRepository<?, ?> repository = getTargetRepository(information, entityManager);
		repository.setRepositoryMethodMetadata(crudMethodMetadataPostProcessor.getCrudMethodMetadata());

		return repository;
	}

来创建Repository的.我们虽然自己的myRepository继承了JpaRepository,但在spring加载时,并不是加载的myRepository,这里是动态加载了一个SimpleJpaRepository在spring容器中,而我们使用@Autowired注解注入myRepository使用时,其实就是在使用SimpleJpaRepository来操作数据.而这里我有一个疑问就是,SimpleJpaRepository只提供了通用的方法的实现,那其他我们自定义在myRepository中的Query方法是如何操作的呢?接着往下看.

我在跟踪项目启动的时候发现,org.springframework.data.repository.core.support.RepositoryFactorySupport下面有一个QueryExecutorMethodInterceptor类,其中一个方法是

public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformation, Object customImplementation,
				Object target) {

			Assert.notNull(repositoryInformation, "RepositoryInformation must not be null!");
			Assert.notNull(target, "Target must not be null!");

			this.resultHandler = new QueryExecutionResultHandler();
			this.repositoryInformation = repositoryInformation;
			this.customImplementation = customImplementation;
			this.target = target;

			QueryLookupStrategy lookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,
					RepositoryFactorySupport.this.evaluationContextProvider);
			lookupStrategy = lookupStrategy == null ? getQueryLookupStrategy(queryLookupStrategyKey) : lookupStrategy;
			Iterable<Method> queryMethods = repositoryInformation.getQueryMethods();

			if (lookupStrategy == null) {

				if (queryMethods.iterator().hasNext()) {
					throw new IllegalStateException("You have defined query method in the repository but "
							+ "you don't have any query lookup strategy defined. The "
							+ "infrastructure apparently does not support query methods!");
				}

				return;
			}

			SpelAwareProxyProjectionFactory factory = new SpelAwareProxyProjectionFactory();
			factory.setBeanClassLoader(classLoader);
			factory.setBeanFactory(beanFactory);

			for (Method method : queryMethods) {

				RepositoryQuery query = lookupStrategy.resolveQuery(method, repositoryInformation, factory, namedQueries);

				invokeListeners(query);
				queries.put(method, query);
			}
		}

 

这里的Iterable<Method> queryMethods = repositoryInformation.getQueryMethods();就是获取的我们自定义在myRepository中的方法,然后将方法存入一个库里面.在执行时,拦截自定义方法,从这里执行自定义方法.

注释是:

/**
		 * Creates a new {@link QueryExecutorMethodInterceptor}. Builds a model of {@link QueryMethod}s to be invoked on
		 * execution of repository interface methods.
		 */

翻译: 创建一个新的{@link QueryExecutorMethodInterceptor}。 构建要调用的{@link QueryMethod}模型
执行存储库接口方法。

到此就是我初步的一些理解了...还有很多不明白的地方..比如RepositoryFactoryBeanSupport,RepositoryFactorySupport,JpaRepositoryFactory的关系.方法时如何在执行时被调用的.既然是生成的动态代理类,那自定义方法是否和通用方法一起封装返回的SimpleJpaRepository中.还有很不清楚的地方.毕竟能力有限还需要慢慢的去探索..

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值