<返回更多

程序员应知应会之Spring Data Jpa为什么不用写@Repository注解?

2022-10-17    活在信息时代
加入收藏

大家知道,在Springboot+Spring Data Jpa的项目里,dao层只需要继承JpaRepository接口,就可以实现MyBatis中@Repository+mApper的效果,不需要任何多余的配置,就可以将dao层注入bean。类似于这样:

public interface BookRepository extends JpaRepository<Book, Long>

这样一句话,就可以实现很多的增删改查效果,例如findAll(),findById()等等,可以说是非常的简单高效。

那么很多刚开始用Spring Data Jpa的同学就会很不理解,为什么这样一句话,就可以实现那么多的功能呢,不添加一个@Repository,心里总有些不踏实的感觉。

那么我们来看一下,Spring Data Jpa是怎么做到的。

一、JpaRepository的继承结构

首先我们来看看JpaRepository的继承结构。很容易看到JpaRepository的定义:

public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>

可以看到JpaRepository继承了两个接口,一个
PagingAndSortingRepository和一个QueryByExampleExecutor。

这两个接口的定义分别是:

public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID>

public interface QueryByExampleExecutor<T>

CrudRepository的定义为

public interface CrudRepository<T, ID> extends Repository<T, ID>

可以看到,最终的继承结果继承到了Repository里面。

而这一系列的继承,就为我们提供了

save(S entity);

saveAll(Iterable<S> entities);

findById(ID id);

existsById(ID id);

findAll();

findAllById(Iterable<ID> ids);

count();

deleteById(ID id);

delete(T entity);

deleteAll(Iterable<? extends T> entities);

deleteAll();

findOne(Example<S> example);

findAll(Example<S> example);

findAll(Example<S> example, Sort sort);

findAll(Example<S> example, Pageable pageable);

count(Example<S> example);

exists(Example<S> example);

findAll(Sort sort);

findAll(Pageable pageable);

等很多的功能。

 

二、JpaRepository为什么不需要@Repository注解

经过简单的Debug,我们就可以轻松定位到Spring注入bean的位置,是在
org.springframework.context.annotation包里面的


ClassPathScanningCandidateComponentProvider类中的

scanCandidateComponents方法里面,其中关键的代码在下面标蓝的

isCandidateComponent(metadataReader)判断里面。

 

而这个函数会将目标接口及其父接口一层层地往上对比,如果与该类自身的

includeFilters中的某个filter比中,则会返回true,意味着该实现将会作为bean被Spring管理起来,从而可以直接用@Autowired引用。

那么我们先来看看includeFilters里面到底有些什么东西,查询代码可以看到,该类在初始化的时候,添加了Component和ManagedBean。很显然,这与我们的Repository还是毫无关系的。事实上也是如此,在Spring启动时,第一遍扫描并没有把我们的BookRepository注入bean。

直到
org.springframework.data.repository.config包中的


RepositoryConfigurationDelegate执行的时候,才会开始扫描,而这个类执行的时候,会启动一个继承了ClassPathScanningCandidateComponentProvider类的RepositoryComponentProvider。

而在这个类里面,我们可以看到Repository最终被加载到了includeFilters里面。

 

此时,再扫描对应的包的时候,继承自Repository的所有dao层类,就被会注入成bean,供人们调用了。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>