Spring Boot 系列文章源于 深入实践Spring Boot 一书(感谢作者)。时过境迁,我使用了更新的版本来学习。写下系列的博客,一则为了加强记忆,便于回顾,再则也希望帮助到正在学习 Spring Boot 的同学。当然,这也算给自己列下了学习计划吧!
本文介绍了如何基于JpaRepository
拓展出更多的通用方法,其它的 repository
只需要从拓展出的接口继承即可。
创建一个ExpandJpaRepository
接口,继承于JpaRepository
,并将接口标记为@NoRepositoryBean
,以防被当作一般的Repository
调用。接口 ExpandJpaRepository
不仅拓展了JPA 原来的方法,而且增加了新的方法:
@NoRepositoryBean
public interface ExpandJpaRepository extends JpaRepository {
T findOne(String condition, Object... objects);
}
这一接口的所有声明方法,必须由我们来实现。
public class ExpandJpaRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T,ID>
implements ExpandJpaRepository<T, ID> {
private final EntityManager entityManager;
private final JpaEntityInformation<T,?> entityInformation;
public ExpandJpaRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager em) {
super(entityInformation, em);
this.entityInformation = entityInformation;
this.entityManager = em;
}
@Override
public T findOne(String condition, Object... objects) {
System.out.println("find one 执行---" + condition);
return null;
}
}
自定义的接口必须在程序启动时装配,才能正常使用。首先,创建一个装配类 ExpandJpaRepositoryFactoryBean
,继承于 JpaRepositoryFactoryBean
,用于加载自定义的拓展接口。
public class ExpandJpaRepositoryFactoryBean<R extends JpaRepository<T, ID>, T, ID extends Serializable> extends JpaRepositoryFactoryBean {
public ExpandJpaRepositoryFactoryBean(Class repositoryInterface) {
super(repositoryInterface);
}
@Override
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
super.setEntityManager(entityManager);
}
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new ExpandJpaRepositoryFactory<T, ID>(entityManager);
}
private static class ExpandJpaRepositoryFactory<T, ID extends Serializable> extends JpaRepositoryFactory{
private final EntityManager entityManager;
public ExpandJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
@Override
protected JpaRepositoryImplementation<?, ?> getTargetRepository(RepositoryInformation information,
EntityManager entityManager) {
JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(information.getDomainType());
return new ExpandJpaRepositoryImpl(entityInformation,entityManager);
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return ExpandJpaRepositoryImpl.class;
}
}
}
其中,getTargetRepository 方法返回自定义的接口实现。
然后,在 JPA 配置类中,通过 @EnableJpaRepositories
加载定义的装配类 ExpandJpaRepositoryFactoryBean
:
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@EnableJpaRepositories(basePackages = {"com.duofei.db.mysql.custom"}, repositoryFactoryBeanClass = ExpandJpaRepositoryFactoryBean.class)
@EntityScan("com.duofei.db.mysql.entity")
public class ExpandJpaConfiguration {
}
现在,来做实体的持久化,这样就可以直接使用自定义的拓展接口了。
@Repository
public interface CustomUserRepository extends ExpandJpaRepository<User, Long> {
}
使用 JPA 拓展接口与使用原来的 JPA 接口一样。
调用自定义实现的 findOne 方法:
@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomExpandTest {
@Autowired
private CustomUserRepository customUserRepository;
@Test
public void expandJPA(){
customUserRepository.findOne("测试");
}
}
成功执行!