如何使用代理解析从 SimpleJpaRepository<T,ID> 对象获取存储库接口对象
How to get Repository Interface object back from SimpleJpaRepository<T,ID> object with proxy resolution
存储库Class
@Repository
public interface AllFileRepository extends JpaRepository<AllFile, Long> {
@Query("SELECT a From AllFile a where a.guid = :guid")
AllFile findByGuid(@Param("guid") String guid);
}
服务Class
@Service
@Data
public class PipelineService implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Autowired
AllFileRepository allFileRepository;
}
正在创建对象 SimpleJpaRepository
PipelineService pipelineService = new PipelineService();
void methodX() {
AnnotationConfigApplicationContext applicationContext = (AnnotationConfigApplicationContext)
ApplicationContextUtils.getApplicationContext();
AutowireCapableBeanFactory autowireCapableBeanFactory =
applicationContext.getAutowireCapableBeanFactory();
autowireCapableBeanFactory.autowireBean(pipelineService);
JpaRepository<AllFile, Long> jpaRepository = (SimpleJpaRepository<AllFile, Long>)
AopProxyUtils.getSingletonTarget(pipelineService.getAllFileRepository());
// (AllFileRepository) jpaRepository casting causes ClassCastException
}
异常
java.lang.ClassCastException: org.springframework.data.jpa.repository.support.SimpleJpaRepository cannot be cast to ....repository.AllFileRepository
如何获取AllFileRepository接口的对象?我可以在哪里访问 findByGuid("");
更新
我能够得到属于接口 AllFileRepository 的 SimpleJpaRepository<AllFile, Long>
的对象,它又扩展了 JpaRepository
public void initialize() {
AnnotationConfigApplicationContext applicationContext = (AnnotationConfigApplicationContext) ApplicationContextUtils
.getApplicationContext();
EntityManager em = applicationContext.getBean(EntityManager.class);
AllFileRepository allFileRepository = new JpaRepositoryFactory(em).getRepository(AllFileRepository.class);
allFileRepository.findByGuid(""); // Method is accessible here but the object is proxy
SimpleJpaRepository<AllFile, Long> simpleJpaRepository = (SimpleJpaRepository<AllFile, Long>) (AopProxyUtils
.getSingletonTarget(allFileRepository)); // But proxy resolution yeilds SimpleJpaRepository cannot
// explicitly cast to AllFileRepository
((AllFileRepository) simpleJpaRepository).findByGuid(""); // class
// org.springframework.data.jpa.repository.support.SimpleJpaRepository
// cannot be cast to class
// com.example.spingaoprepository.repository.AllFileRepository
// (org.springframework.data.jpa.repository.support.SimpleJpaRepository
// and
// com.example.spingaoprepository.repository.AllFileRepository
// are in unnamed module of loader 'app'
}
这里有一个link来采样program
使用@Autowired,您正在注入一个实现AllFileRepository 的对象。此单例是在启动时创建的,因此您可以将 is 与 allFileRepository.findByGuid("");
一起使用
您正在使用 new
关键字实例化您的 PipelineService,然后在您的 methodX() 中手动获取 Spring 上下文。
原则上,您当然 'could' 无需 Spring 手动完成所有操作。但是鉴于您的存储库和服务都是 Spring beans,那么最好让 Spring 处理 bean 生命周期。无论如何,这肯定更容易。
由于 PipelineService 是一个 Spring bean,因此您真的应该让使用它的任何 class Spring 也知道。因此,只需使用 Spring 注释来注释 class,例如 @Component
、@Service
,或者如果它是控制器,则可能 @RestController
。
如果您坚持手动创建 bean,请尝试 -
ApplicationContext context = new AnnotationConfigApplicationContext();
PipelineService pipelineService = context.getBean(PipelineService.class);
尝试将不兼容的类型相互转换是没有用的。这不是 Spring 问题,而是 Java 基础知识。我已经在 Spring 中告诉过您如何解决该问题:您需要提供一个 class 实际实现 AllFileRepository
并确保 Spring Data JPA 将其用作存储库的界面。为此,您需要
- 将接口注释由
@Repository
更改为@NoRepositoryBean
,
- 创建 class
@Repository AllFileRepositoryImpl
并提供 AllFile findByGuid(String guid)
做一些有意义的事情的实现。
然后您可以轻松地按照您想要的方式进行转换,因为您的代理的目标对象将是一个 AllFileRepositoryImpl
实例。
我给你发了一个pull request which you just need to accept. The classes changed in the relevant commit @5705cbb如下图:
package com.example.spingaoprepository.repository;
import com.example.spingaoprepository.model.AllFile;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface AllFileRepository extends JpaRepository<AllFile, Long> {
@Query("SELECT a From AllFile a where a.guid = :guid")
AllFile findByGuid(@Param("guid") String guid);
}
package com.example.spingaoprepository.repository;
import com.example.spingaoprepository.model.AllFile;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
@Repository
public class AllFileRepositoryImpl extends SimpleJpaRepository<AllFile, Long> implements AllFileRepository {
public AllFileRepositoryImpl(EntityManager em) {
super(AllFile.class, em);
}
@Override
public AllFile findByGuid(String guid) {
System.out.println("Finding AllFile by GUID " + guid);
return null;
}
}
package com.example.spingaoprepository.serializable;
import com.example.spingaoprepository.repository.AllFileRepository;
import com.example.spingaoprepository.service.PipelineService;
import com.example.spingaoprepository.utils.ApplicationContextUtils;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
public class PipelineConfigurer {
private ApplicationContext applicationContext = ApplicationContextUtils.getApplicationContext();
private PipelineService pipelineService = applicationContext.getBean(PipelineService.class);
public void initialize() {
AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
autowireCapableBeanFactory.autowireBean(pipelineService);
AllFileRepository allFileRepository = (AllFileRepository) AopProxyUtils
.getSingletonTarget(pipelineService.getAllFileRepository());
allFileRepository.findByGuid("XY-123");
}
}
存储库Class
@Repository
public interface AllFileRepository extends JpaRepository<AllFile, Long> {
@Query("SELECT a From AllFile a where a.guid = :guid")
AllFile findByGuid(@Param("guid") String guid);
}
服务Class
@Service
@Data
public class PipelineService implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Autowired
AllFileRepository allFileRepository;
}
正在创建对象 SimpleJpaRepository
PipelineService pipelineService = new PipelineService();
void methodX() {
AnnotationConfigApplicationContext applicationContext = (AnnotationConfigApplicationContext)
ApplicationContextUtils.getApplicationContext();
AutowireCapableBeanFactory autowireCapableBeanFactory =
applicationContext.getAutowireCapableBeanFactory();
autowireCapableBeanFactory.autowireBean(pipelineService);
JpaRepository<AllFile, Long> jpaRepository = (SimpleJpaRepository<AllFile, Long>)
AopProxyUtils.getSingletonTarget(pipelineService.getAllFileRepository());
// (AllFileRepository) jpaRepository casting causes ClassCastException
}
异常
java.lang.ClassCastException: org.springframework.data.jpa.repository.support.SimpleJpaRepository cannot be cast to ....repository.AllFileRepository
如何获取AllFileRepository接口的对象?我可以在哪里访问 findByGuid("");
更新
我能够得到属于接口 AllFileRepository 的 SimpleJpaRepository<AllFile, Long>
的对象,它又扩展了 JpaRepository
public void initialize() {
AnnotationConfigApplicationContext applicationContext = (AnnotationConfigApplicationContext) ApplicationContextUtils
.getApplicationContext();
EntityManager em = applicationContext.getBean(EntityManager.class);
AllFileRepository allFileRepository = new JpaRepositoryFactory(em).getRepository(AllFileRepository.class);
allFileRepository.findByGuid(""); // Method is accessible here but the object is proxy
SimpleJpaRepository<AllFile, Long> simpleJpaRepository = (SimpleJpaRepository<AllFile, Long>) (AopProxyUtils
.getSingletonTarget(allFileRepository)); // But proxy resolution yeilds SimpleJpaRepository cannot
// explicitly cast to AllFileRepository
((AllFileRepository) simpleJpaRepository).findByGuid(""); // class
// org.springframework.data.jpa.repository.support.SimpleJpaRepository
// cannot be cast to class
// com.example.spingaoprepository.repository.AllFileRepository
// (org.springframework.data.jpa.repository.support.SimpleJpaRepository
// and
// com.example.spingaoprepository.repository.AllFileRepository
// are in unnamed module of loader 'app'
}
这里有一个link来采样program
使用@Autowired,您正在注入一个实现AllFileRepository 的对象。此单例是在启动时创建的,因此您可以将 is 与 allFileRepository.findByGuid("");
您正在使用 new
关键字实例化您的 PipelineService,然后在您的 methodX() 中手动获取 Spring 上下文。
原则上,您当然 'could' 无需 Spring 手动完成所有操作。但是鉴于您的存储库和服务都是 Spring beans,那么最好让 Spring 处理 bean 生命周期。无论如何,这肯定更容易。
由于 PipelineService 是一个 Spring bean,因此您真的应该让使用它的任何 class Spring 也知道。因此,只需使用 Spring 注释来注释 class,例如 @Component
、@Service
,或者如果它是控制器,则可能 @RestController
。
如果您坚持手动创建 bean,请尝试 -
ApplicationContext context = new AnnotationConfigApplicationContext();
PipelineService pipelineService = context.getBean(PipelineService.class);
尝试将不兼容的类型相互转换是没有用的。这不是 Spring 问题,而是 Java 基础知识。我已经在 Spring 中告诉过您如何解决该问题:您需要提供一个 class 实际实现 AllFileRepository
并确保 Spring Data JPA 将其用作存储库的界面。为此,您需要
- 将接口注释由
@Repository
更改为@NoRepositoryBean
, - 创建 class
@Repository AllFileRepositoryImpl
并提供AllFile findByGuid(String guid)
做一些有意义的事情的实现。
然后您可以轻松地按照您想要的方式进行转换,因为您的代理的目标对象将是一个 AllFileRepositoryImpl
实例。
我给你发了一个pull request which you just need to accept. The classes changed in the relevant commit @5705cbb如下图:
package com.example.spingaoprepository.repository;
import com.example.spingaoprepository.model.AllFile;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface AllFileRepository extends JpaRepository<AllFile, Long> {
@Query("SELECT a From AllFile a where a.guid = :guid")
AllFile findByGuid(@Param("guid") String guid);
}
package com.example.spingaoprepository.repository;
import com.example.spingaoprepository.model.AllFile;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
@Repository
public class AllFileRepositoryImpl extends SimpleJpaRepository<AllFile, Long> implements AllFileRepository {
public AllFileRepositoryImpl(EntityManager em) {
super(AllFile.class, em);
}
@Override
public AllFile findByGuid(String guid) {
System.out.println("Finding AllFile by GUID " + guid);
return null;
}
}
package com.example.spingaoprepository.serializable;
import com.example.spingaoprepository.repository.AllFileRepository;
import com.example.spingaoprepository.service.PipelineService;
import com.example.spingaoprepository.utils.ApplicationContextUtils;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
public class PipelineConfigurer {
private ApplicationContext applicationContext = ApplicationContextUtils.getApplicationContext();
private PipelineService pipelineService = applicationContext.getBean(PipelineService.class);
public void initialize() {
AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
autowireCapableBeanFactory.autowireBean(pipelineService);
AllFileRepository allFileRepository = (AllFileRepository) AopProxyUtils
.getSingletonTarget(pipelineService.getAllFileRepository());
allFileRepository.findByGuid("XY-123");
}
}