解释“dao”这个bean。这里衍生一下,进行一下名词解释,我们知道dao这个层叫做Data Access Object,数据库访问对象,这是一个广泛的词语,在jpa当中,我们还有一个词语叫做Repository,这里我们一般就用Repository结尾来表示这个dao,比如UserDao,这里我们使用UserRepository,当然名字无所谓,随意取,你可以意会一下我的意思,感受一下这里的含义和区别,同理,在mybatis中我们一般也不叫dao,mybatis由于使用xml映射文件(当然也提供注解,但是官方文档上面表示在有些地方,比如多表的复杂查询方面,注解还是无解,只能xml),我们一般使用mapper结尾,比如我们也不叫UserDao,而叫UserMapper。
然而,我们的UserRepository和UserRepositoryImpl这两个类就像下面这样来写。
public interface UserRepository extends JpaRepository{}
public class UserRepositoryImpl {}
那么这里为什么要这么做呢?原因是:spring-data-jpa提供基础的CRUD工作,同时也提供业务逻辑的功能(前面说了,这是该框架的威力所在),所以我们的Repository接口要做两项工作,继承spring-data-jpa提供的基础CRUD功能的接口,比如JpaRepository接口,同时自己还需要在UserRepository这个接口中定义自己的方法,那么导致的结局就是UserRepository这个接口中有很多的方法,那么如果我们的UserRepositoryImpl实现了UserRepository接口,导致的后果就是我们势必需要重写里面的所有方法,这是Java语法的规定,如此一来,悲剧就产生了,UserRepositoryImpl里面我们有很多的@Override方法,这显然是不行的,结论就是,这里我们不用去写implements部分。
spring-data-jpa实现了上面的能力,那他是怎么实现的呢?这里我们通过源代码的方式来呈现他的来龙去脉,这个过程中cglib发挥了杰出的作用。
在spring-data-jpa内部,有一个类,叫做:
public class SimpleJpaRepository implements JpaRepository, JpaSpecificationExecutor
我们可以看到这个类是实现了JpaRepository接口的,事实上如果我们按照上面的配置,在同一个包下面有UserRepository,但是没有UserRepositoryImpl这个类的话,在运行时期UserRepository这个接口的实现就是上面的SimpleJpaRepository这个接口。而如果有UserRepositoryImpl这个文件的话,那么UserRepository的实现类就是UserRepositoryImpl,而UserRepositoryImpl这个类又是SimpleJpaRepository的子类,如此一来就很好的解决了上面的这个不用写implements的问题。我们通过阅读这个类的源代码可以发现,里面包装了entityManager,底层的调用关系还是entityManager在进行CRUD。
spring-data-jpa为什么把Repository和RepositoryImpl文件放在同一个包下面,因为我们的应用很可能根本就一个Impl文件都不存在,那么在那个包下面就只有一堆接口,即使把Repository和RepositoryImpl都放在同一个包下面,也不会造成这个包下面有正常情况下2倍那么多的文件,根本原因:只有接口而没有实现类。
UserRepository类继承了JpaRepository和JpaSpecificationExecutor类,而我们的UserReposit-ory这个对象都会注入到UserService里面,于是如果使用这种方式,我们的逻辑直接就写在service里面了