SpringBoot如何拓展 JPA Repository

文章目录

  • 1. 拓展JPA接口
  • 2. 装配自定义的拓展接口
  • 3. 使用拓展接口
  • 4. 测试

写在前面

Spring Boot 系列文章源于 深入实践Spring Boot 一书(感谢作者)。时过境迁,我使用了更新的版本来学习。写下系列的博客,一则为了加强记忆,便于回顾,再则也希望帮助到正在学习 Spring Boot 的同学。当然,这也算给自己列下了学习计划吧!


本文介绍了如何基于JpaRepository 拓展出更多的通用方法,其它的 repository 只需要从拓展出的接口继承即可。


1. 拓展JPA接口

创建一个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;
    }
}

2. 装配自定义的拓展接口

自定义的接口必须在程序启动时装配,才能正常使用。首先,创建一个装配类 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 {

}

3. 使用拓展接口

现在,来做实体的持久化,这样就可以直接使用自定义的拓展接口了。

@Repository
public interface CustomUserRepository extends ExpandJpaRepository<User, Long> {
}

使用 JPA 拓展接口与使用原来的 JPA 接口一样。

4. 测试

调用自定义实现的 findOne 方法:

@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomExpandTest {

    @Autowired
    private CustomUserRepository customUserRepository;

    @Test
    public void expandJPA(){
        customUserRepository.findOne("测试");
    }
}

成功执行!

你可能感兴趣的:(SpringBoot)