[英]Spring Boot Inject Bean Map with Generic Type
弹簧框架 5
我有一个数据库实体的实例,我想使用该实体的对应存储库。 如何注入实体映射的所有 JPA 存储库作为键?
例如:
public interface ARepository extends JpaRepository<AEntity, Long> {}
public interface BRepository extends JpaRepository<BEntity, Long> {}
在我的服务组件中:
public class TestService {
@Autowired
private Map<Class, JpaRepository<?, ?>> jpaRepositories;
public <T> List<T> findAll(T entity) {
Class entityClass = entity.getClass();
JpaRepository<?, ?> jpaRepository = jpaRepositories.get(entityClass);
return jpaRepository.findAll();
}
}
我希望jpaRepositories
被注入这些值:
{ AEntity.class, ARepository }, { BEntity.class, BRepository }
默认情况下,这种映射在运行时不可用。 如果您喜欢 hacky 方法并且真的需要它,您可以为 JPA 存储库创建这样的映射:
package com.example.repo;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.util.ProxyUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class AppRunner implements ApplicationRunner {
private static final Logger log = LoggerFactory.getLogger(AppRunner.class);
private final Collection<JpaRepository<?, ?>> jpaRepositories;
@Override
public void run(ApplicationArguments args) throws Exception {
Function<JpaRepository<?, ?>, Class<?>> repositoryClass = r -> {
if (SimpleJpaRepository.class.isAssignableFrom(ProxyUtils.getUserClass(r))) {
Method method = ReflectionUtils.findMethod(SimpleJpaRepository.class, "getDomainClass");
ReflectionUtils.makeAccessible(method);
return (Class<?>) ReflectionUtils.invokeMethod(method, AopProxyUtils.getSingletonTarget(r));
}
return Void.class;
};
Map<Class<?>, JpaRepository<?, ?>> jpaRepositoriesByClass = jpaRepositories.stream().collect(Collectors.toMap(repositoryClass, Function.identity()));
log.info("{}", jpaRepositoriesByClass);
}
}
这是我的解决方案:
@Bean
public Map<Class<?>, JpaRepository<?, ?>> jpaRepositoryMap(
List<JpaRepository<?, ?>> jpaRepositories
) {
return jpaRepositories.stream()
.collect(Collectors.toMap(
jpaRepository -> resolveGenericType(jpaRepository, 0),
Function.identity()
));
}
private Class<?> resolveGenericType(Object object, int index) {
return ResolvableType.forClass(JpaRepository.class, object.getClass())
.getGenerics()[index].resolve();
}
Spring 有ResolvableType
作为获取类的泛型类型的实用程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.