- * 当检测到 Elasticsearch 相关依赖({@link org.springframework.data.elasticsearch.core.ElasticsearchOperations})时自动配置, - * 注册 Elasticsearch 文档操作所需的核心组件,使其与仓储框架无缝集成。 - *
- * 注册的 Bean: - *
- * 工作机制: - *
- * 配置方式: - *
- * 额外配置: - *
- * 负责根据 PO 类创建 ElasticsearchRepositoryDelegate 实例,通过 ElasticsearchOperations 进行文档操作。 - * 当 RepositoryFacade 需要获取 Elasticsearch 类型的 RepositoryDelegate 时,会通过此工厂进行创建。 - * - * @param elasticsearchOperations Elasticsearch 操作模板,用于执行索引、查询等操作 - * @return ElasticsearchDelegateFactory 实例 - */ - @Bean - @ConditionalOnBean(ElasticsearchOperations.class) - public ElasticsearchDelegateFactory elasticsearchDelegateFactory(ElasticsearchOperations elasticsearchOperations) { - return new ElasticsearchDelegateFactory(elasticsearchOperations); - } - - /** - * 创建 Elasticsearch 委托 Bean 后处理器 - *
- * 在 Bean 初始化完成后,自动为 ElasticsearchRepositoryDelegate 实现类注入 ElasticsearchOperations 和实体类。 - *
- * 处理逻辑: - * 1. 扫描所有 Bean,筛选出 ElasticsearchRepositoryDelegate 的实例 - * 2. 从 Spring 上下文获取 ElasticsearchOperations 并注入到 Delegate 实例中 - * 3. 检查是否存在 {@link cn.structure.infra.annotations.DelegateFor} 注解 - * 4. 将注解中指定的 PO 类设置到 Delegate 实例中 - * - * @return ElasticsearchDelegateBeanPostProcessor 实例 - */ - @Bean - @ConditionalOnBean(ElasticsearchOperations.class) - public ElasticsearchDelegateBeanPostProcessor elasticsearchDelegateBeanPostProcessor() { - return new ElasticsearchDelegateBeanPostProcessor(); - } } diff --git a/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchDelegateBeanPostProcessor.java b/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchDelegateBeanPostProcessor.java deleted file mode 100644 index 23c27b0..0000000 --- a/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchDelegateBeanPostProcessor.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.structure.infra.elasticsearch.repository; - -import cn.structure.infra.annotations.DelegateFor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.data.elasticsearch.core.ElasticsearchOperations; - -/** - * Elasticsearch RepositoryDelegate 的 BeanPostProcessor,负责为用户自定义 Delegate 子类自动注入 ElasticsearchOperations 与实体类型。 - *
- * 在仓储框架中,业务方可继承 {@link ElasticsearchRepositoryDelegate} 实现自定义 Delegate,并通过 - * {@link DelegateFor} 注解声明其服务的 PO 类型。本后处理器在 Bean 初始化完成后: - *
- * 与 {@link ElasticsearchDelegateFactory} 的分工:工厂负责"无自定义 Delegate 时自动创建", - * 本处理器负责"已有自定义 Delegate 时补齐依赖",二者协同保证 RepositoryFacade 总能拿到可用的 Delegate。 - * - * @author chuck - * @version 1.0.1 - * @since 2026/6/28 - */ -@Slf4j -public class ElasticsearchDelegateBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware { - - /** Spring 上下文,用于按类型获取 ElasticsearchOperations */ - private ApplicationContext applicationContext; - - /** - * 注入 Spring 应用上下文,供后续按类型查询 Bean。 - * - * @param applicationContext Spring 应用上下文 - * @throws BeansException 上下文注入异常 - */ - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - /** - * 在 Bean 初始化完成后,对自定义 ElasticsearchRepositoryDelegate 实现类注入 ElasticsearchOperations 与实体类型。 - *
- * 仅当 Bean 是 {@link ElasticsearchRepositoryDelegate} 实例时执行注入; - * ElasticsearchOperations 解析失败仅告警不抛异常。 - * - * @param bean 待处理的 Bean 实例 - * @param beanName Bean 名称 - * @return 原始 Bean(已注入依赖),未匹配类型时原样返回 - * @throws BeansException 处理过程中的异常 - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (bean instanceof ElasticsearchRepositoryDelegate) { - ElasticsearchRepositoryDelegate delegate = (ElasticsearchRepositoryDelegate) bean; - try { - // 按类型从容器获取 ElasticsearchOperations 并注入 - ElasticsearchOperations elasticsearchOperations = applicationContext.getBean(ElasticsearchOperations.class); - delegate.setElasticsearchOperations(elasticsearchOperations); - - // 读取 @DelegateFor 注解,识别该 Delegate 服务的 PO 类型并注入 - DelegateFor annotation = bean.getClass().getAnnotation(DelegateFor.class); - if (annotation != null && annotation.po() != void.class) { - delegate.setEntityClass(annotation.po()); - } - - log.info("Injected ElasticsearchOperations into ElasticsearchRepositoryDelegate: {}", beanName); - } catch (Exception e) { - log.warn("Failed to inject ElasticsearchOperations into ElasticsearchRepositoryDelegate {}: {}", beanName, e.getMessage()); - } - } - return bean; - } -} \ No newline at end of file diff --git a/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchDelegateFactory.java b/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchDelegateFactory.java deleted file mode 100644 index d855024..0000000 --- a/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchDelegateFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.structure.infra.elasticsearch.repository; - -import cn.structure.infra.repository.RepositoryDelegate; -import cn.structure.infra.repository.RepositoryDelegateFactory; -import cn.structure.infra.repository.RepositoryType; -import org.springframework.data.elasticsearch.core.ElasticsearchOperations; - -/** - * Elasticsearch 仓储委托工厂 - *
- * 实现 {@link RepositoryDelegateFactory} SPI,自动创建 {@link ElasticsearchRepositoryDelegate} 实例。 - * 在仓储框架中,当 {@code RepositoryFacade} 找不到用户自定义的 Delegate 时,会通过本工厂按 PO 类型 - * 创建默认 Delegate 实例(依赖容器中的 {@link ElasticsearchOperations})。 - *
- * 与 {@link ElasticsearchDelegateBeanPostProcessor} 的分工:本工厂负责"无自定义 Delegate 时创建默认实现", - * BeanPostProcessor 负责"已有自定义子类时补齐依赖"。 - * - * @author chuck - * @version 1.0.1 - * @since 2026/6/28 - */ -public class ElasticsearchDelegateFactory implements RepositoryDelegateFactory { - - /** Elasticsearch 操作模板,由容器注入并共享给所有 Delegate 实例 */ - private final ElasticsearchOperations elasticsearchOperations; - - /** - * 构造工厂,注入 ElasticsearchOperations。 - * - * @param elasticsearchOperations Elasticsearch 操作模板 - */ - public ElasticsearchDelegateFactory(ElasticsearchOperations elasticsearchOperations) { - this.elasticsearchOperations = elasticsearchOperations; - } - - /** - * 返回该工厂支持的仓储类型,用于 SPI 路由匹配。 - * - * @return 固定返回 {@link RepositoryType#ELASTICSEARCH} - */ - @Override - public RepositoryType getType() { - return RepositoryType.ELASTICSEARCH; - } - - /** - * 为指定 PO 类型创建 {@link ElasticsearchRepositoryDelegate} 实例。 - *
- * Elasticsearch 实现不依赖 Mapper 查找,直接以入参 PO 类型构造 Delegate,因此失败概率较低; - * 出现异常时返回 null,由上层 RepositoryFacade 继续尝试其他工厂或抛出异常。 - * - * @param poClass PO 实体类型 - * @param idClass 主键类型(当前实现未使用,保留以匹配 SPI 签名) - * @return 已注入 ElasticsearchOperations 的 Delegate 实例;构造异常时返回 null - */ - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - public RepositoryDelegate, ?> createDelegate(Class> poClass, Class> idClass) { - try { - return new ElasticsearchRepositoryDelegate(elasticsearchOperations, poClass); - } catch (Exception e) { - return null; - } - } -} diff --git a/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchRepositoryDelegate.java b/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchRepositoryDelegate.java index 2bfe80c..53d7d7a 100644 --- a/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchRepositoryDelegate.java +++ b/structure-infra-elasticsearch-starter/src/main/java/cn/structure/infra/elasticsearch/repository/ElasticsearchRepositoryDelegate.java @@ -2,8 +2,11 @@ import cn.structure.common.vo.ReqPage; import cn.structure.common.vo.ResPage; +import cn.structure.infra.repository.GenericTypeResolver; import cn.structure.infra.repository.RepositoryDelegate; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.elasticsearch.core.ElasticsearchOperations; @@ -12,6 +15,7 @@ import org.springframework.data.elasticsearch.core.query.CriteriaQuery; import org.springframework.data.elasticsearch.core.query.Query; +import jakarta.persistence.Id; import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; @@ -33,229 +37,164 @@ * 实现说明: *
持久化对象类型(ES Document)
* @param
- * 创建后由 {@link ElasticsearchDelegateBeanPostProcessor} 通过 setter 注入依赖。
- */
+ protected Class poClass;
+ protected Class ) GenericTypeResolver.resolvePoClass(getClass());
+ this.idClass = (Class
- * 委托给 {@link ElasticsearchOperations#save(Object)},由 ES 依据 _id 自动判断新增或覆盖索引。
- *
- * @param entity 实体对象,为 null 时返回 null
- * @return 保存后的实体(与入参同一引用)
- */
@Override
- public T save(T entity) {
+ public E save(E entity) {
if (entity == null) {
return null;
}
- T saved = elasticsearchOperations.save(entity);
- log.debug("Saved entity: {}", saved);
- return saved;
+ P po = toPo(entity);
+ P savedPo = elasticsearchOperations.save(po);
+ log.debug("Saved entity: {}", savedPo);
+ return toEntity(savedPo);
}
- /**
- * 根据主键删除文档。
- *
- * ES 文档 ID 必须为字符串,主键值通过 {@code String.valueOf(id)} 转换后再删除。
- *
- * @param id 主键值,为 null 时不执行任何操作
- */
@Override
public void removeById(ID id) {
if (id != null) {
- // ID 统一转换为 String 作为 ES 文档 ID
- elasticsearchOperations.delete(String.valueOf(id), entityClass);
+ elasticsearchOperations.delete(String.valueOf(id), poClass);
log.debug("Removed entity: id={}", id);
}
}
- /**
- * 根据主键查询文档。
- *
- * ES 文档 ID 必须为字符串,主键值通过 {@code String.valueOf(id)} 转换后再查询。
- *
- * @param id 主键值,为 null 时返回 null
- * @return 实体对象,未找到时返回 null
- */
@Override
- public T findById(ID id) {
+ public E findById(ID id) {
if (id == null) {
return null;
}
- // ID 统一转换为 String 作为 ES 文档 ID
- T entity = elasticsearchOperations.get(String.valueOf(id), entityClass);
- log.debug("Find by id: id={}, found={}", id, entity != null);
- return entity;
+ P po = elasticsearchOperations.get(String.valueOf(id), poClass);
+ log.debug("Find by id: id={}, found={}", id, po != null);
+ return toEntity(po);
}
- /**
- * 根据主键查询(与 findById 等价,语义上用于"读模型",常作为 CQRS 读侧)。
- *
- * @param id 主键值
- * @return 实体对象,未找到时返回 null
- */
@Override
- public T queryById(ID id) {
+ public E queryById(ID id) {
return findById(id);
}
- /**
- * 根据主键查询并以 {@link Optional} 包装返回。
- *
- * @param id 主键值
- * @return 包含实体的 Optional,未找到时为 {@link Optional#empty()}
- */
@Override
- public Optional
- * 通过反射构建 {@link CriteriaQuery},取首条 SearchHit 的 content;无匹配时返回 null。
- *
- * @param condition 查询条件对象,为 null 时返回 null
- * @return 首条匹配记录,无匹配时返回 null
- */
@Override
- public T queryOne(T condition) {
+ public E queryOne(E condition) {
if (condition == null) {
return null;
}
- Query query = buildQuery(condition);
- SearchHits searchHits = elasticsearchOperations.search(query, poClass);
+ P po = searchHits.hasSearchHits() ? searchHits.getSearchHit(0).getContent() : null;
+ return toEntity(po);
}
- /**
- * 根据条件查询单条记录,并以 {@link Optional} 包装返回。
- *
- * @param condition 查询条件对象
- * @return 包含首条匹配记录的 Optional
- */
@Override
- public Optional
- * 条件为 null 时使用 {@code Criteria.where("*").exists()} 匹配全部文档;
- * 否则按非空字段构建等值 Criteria。
- *
- * @param condition 查询条件对象,可为 null
- * @return 匹配的实体列表,无匹配时返回空列表
- */
@Override
- public List searchHits = elasticsearchOperations.search(query, poClass);
return searchHits.getSearchHits().stream()
- .map(hit -> hit.getContent())
+ .map(hit -> toEntity(hit.getContent()))
.collect(Collectors.toList());
}
- Query query = buildQuery(condition);
- SearchHits searchHits = elasticsearchOperations.search(query, poClass);
return searchHits.getSearchHits().stream()
- .map(hit -> hit.getContent())
+ .map(hit -> toEntity(hit.getContent()))
.collect(Collectors.toList());
}
- /**
- * 分页查询。
- *
- * 通过 {@code Criteria.where("*").exists()} 匹配全部文档,叠加 {@link PageRequest} 分页参数,
- * 由 ES 原生分页(from/size)执行。
- *
- * @param reqPage 分页请求(页码从 1 开始、每页大小,为 null 时取默认 1/10)
- * @return 分页结果,含当前页、总页数、总条数、当前页记录
- */
@Override
- public ResPage searchHits = elasticsearchOperations.search(query, poClass);
- ResPage
- * 当检测到 JPA 相关依赖({@link org.springframework.data.jpa.repository.JpaRepository})时自动配置,
- * 注册 JPA 持久化所需的核心组件,使其与仓储框架无缝集成。
- *
- * 注册的 Bean:
- *
- * 工作机制:
- *
- * 额外配置:
- *
- * 负责根据 PO 类创建 JpaRepositoryDelegate 实例,通过 EntityManager 进行持久化操作。
- * 当 RepositoryFacade 需要获取 JPA 类型的 RepositoryDelegate 时,会通过此工厂进行创建。
- *
- * @param entityManager JPA 实体管理器,用于执行数据库操作
- * @return JpaDelegateFactory 实例
- */
- @Bean
- @ConditionalOnBean(EntityManager.class)
- public JpaDelegateFactory jpaDelegateFactory(EntityManager entityManager) {
- return new JpaDelegateFactory(entityManager);
- }
-
- /**
- * 创建 JPA 委托 Bean 后处理器
- *
- * 在 Bean 初始化完成后,自动为 JpaRepositoryDelegate 实现类注入 EntityManager 和实体类。
- *
- * 处理逻辑:
- * 1. 扫描所有 Bean,筛选出 JpaRepositoryDelegate 的实例
- * 2. 从 Spring 上下文获取 EntityManager 并注入到 Delegate 实例中
- * 3. 检查是否存在 {@link cn.structure.infra.annotations.DelegateFor} 注解
- * 4. 将注解中指定的 PO 类设置到 Delegate 实例中
- *
- * @return JpaDelegateBeanPostProcessor 实例
- */
- @Bean
- @ConditionalOnClass(name = "jakarta.persistence.EntityManager")
- public JpaDelegateBeanPostProcessor jpaDelegateBeanPostProcessor() {
- return new JpaDelegateBeanPostProcessor();
- }
}
diff --git a/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaDelegateBeanPostProcessor.java b/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaDelegateBeanPostProcessor.java
deleted file mode 100644
index 95d4871..0000000
--- a/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaDelegateBeanPostProcessor.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package cn.structure.infra.jpa.repository;
-
-import cn.structure.infra.annotations.DelegateFor;
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.EntityManagerFactory;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanPostProcessor;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-
-/**
- * JPA RepositoryDelegate 的 BeanPostProcessor,负责为用户自定义 Delegate 子类自动注入 EntityManager 与实体类型。
- *
- * 在仓储框架中,业务方可继承 {@link JpaRepositoryDelegate} 实现自定义 Delegate,并通过
- * {@link DelegateFor} 注解声明其服务的 PO 类型。本后处理器在 Bean 初始化完成后:
- *
- * 与 {@link JpaDelegateFactory} 的分工:工厂负责"无自定义 Delegate 时自动创建",
- * 本处理器负责"已有自定义 Delegate 时补齐依赖",二者协同保证 RepositoryFacade 总能拿到可用的 Delegate。
- *
- * @author chuck
- * @version 1.0.1
- * @since 2026/6/28
- */
-@Slf4j
-public class JpaDelegateBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
-
- /** Spring 上下文,用于解析 EntityManager */
- private ApplicationContext applicationContext;
-
- /**
- * 注入 Spring 应用上下文,供后续按类型/名称查询 Bean。
- *
- * @param applicationContext Spring 应用上下文
- * @throws BeansException 上下文注入异常
- */
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- /**
- * 在 Bean 初始化完成后,对自定义 JpaRepositoryDelegate 实现类注入 EntityManager 与实体类型。
- *
- * 仅当 Bean 是 {@link JpaRepositoryDelegate} 实例时执行注入;EntityManager 解析失败仅告警不抛异常。
- *
- * @param bean 待处理的 Bean 实例
- * @param beanName Bean 名称
- * @return 原始 Bean(已注入依赖),未匹配类型时原样返回
- * @throws BeansException 处理过程中的异常
- */
- @SuppressWarnings({"unchecked", "rawtypes"})
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof JpaRepositoryDelegate) {
- JpaRepositoryDelegate delegate = (JpaRepositoryDelegate) bean;
-
- // 解析 EntityManager:by name → by type → create
- EntityManager entityManager = getEntityManager();
- if (entityManager != null) {
- delegate.setEntityManager(entityManager);
- log.info("Injected EntityManager into JpaRepositoryDelegate: {}", beanName);
- } else {
- log.warn("No EntityManager available to inject into JpaRepositoryDelegate: {}", beanName);
- }
-
- // 读取 @DelegateFor 注解,识别该 Delegate 服务的 PO 类型并注入
- DelegateFor annotation = bean.getClass().getAnnotation(DelegateFor.class);
- if (annotation != null && annotation.po() != void.class) {
- delegate.setEntityClass(annotation.po());
- log.info("Injected entityClass {} into JpaRepositoryDelegate: {}", annotation.po().getSimpleName(), beanName);
- }
- }
- return bean;
- }
-
- /**
- * 解析 {@link EntityManager} 实例。
- *
- * 解析顺序(按优先级):
- *
- * 实现 {@link RepositoryDelegateFactory} SPI,自动创建 {@link JpaRepositoryDelegate} 实例。
- * 在仓储框架中,当 {@code RepositoryFacade} 找不到用户自定义的 Delegate 时,会通过本工厂按 PO 类型
- * 创建默认 Delegate 实例(依赖容器中的 {@link EntityManager})。
- *
- * 与 {@link JpaDelegateBeanPostProcessor} 的分工:本工厂负责"无自定义 Delegate 时创建默认实现",
- * BeanPostProcessor 负责"已有自定义子类时补齐依赖"。
- *
- * @author chuck
- * @version 1.0.1
- * @since 2026/6/28
- */
-public class JpaDelegateFactory implements RepositoryDelegateFactory {
-
- /** JPA 实体管理器,由容器注入并共享给所有 Delegate 实例 */
- private final EntityManager entityManager;
-
- /**
- * 构造工厂,注入 EntityManager。
- *
- * @param entityManager JPA 实体管理器,用于执行持久化操作
- */
- public JpaDelegateFactory(EntityManager entityManager) {
- this.entityManager = entityManager;
- }
-
- /**
- * 返回该工厂支持的仓储类型,用于 SPI 路由匹配。
- *
- * @return 固定返回 {@link RepositoryType#JPA}
- */
- @Override
- public RepositoryType getType() {
- return RepositoryType.JPA;
- }
-
- /**
- * 为指定 PO 类型创建 {@link JpaRepositoryDelegate} 实例。
- *
- * JPA 实现不依赖 Mapper 查找,直接以入参 PO 类型构造 Delegate,因此失败概率较低;
- * 出现异常时返回 null,由上层 RepositoryFacade 继续尝试其他工厂或抛出异常。
- *
- * @param poClass PO 实体类型
- * @param idClass 主键类型(当前实现未使用,保留以匹配 SPI 签名)
- * @return 已注入 EntityManager 的 Delegate 实例;构造异常时返回 null
- */
- @Override
- @SuppressWarnings({"unchecked", "rawtypes"})
- public RepositoryDelegate, ?> createDelegate(Class> poClass, Class> idClass) {
- try {
- return new JpaRepositoryDelegate(entityManager, poClass);
- } catch (Exception e) {
- return null;
- }
- }
-}
diff --git a/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaRepositoryDelegate.java b/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaRepositoryDelegate.java
index 6ce7983..168399b 100644
--- a/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaRepositoryDelegate.java
+++ b/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaRepositoryDelegate.java
@@ -2,11 +2,11 @@
import cn.structure.common.vo.ReqPage;
import cn.structure.common.vo.ResPage;
+import cn.structure.infra.repository.GenericTypeResolver;
import cn.structure.infra.repository.RepositoryDelegate;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageImpl;
-import org.springframework.data.domain.PageRequest;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
@@ -14,10 +14,12 @@
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
+import jakarta.persistence.Id;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import java.util.stream.Collectors;
/**
* 基于 JPA 的 RepositoryDelegate 适配实现
@@ -36,259 +38,234 @@
* 持久化对象类型(JPA Entity)
* @param
- * 创建后由 {@link JpaDelegateBeanPostProcessor} 通过 setter 注入依赖。
- */
+ protected Class poClass;
+ protected Class ) GenericTypeResolver.resolvePoClass(getClass());
+ this.idClass = (Class
- * 委托给 {@link EntityManager#merge(Object)},由 JPA 根据实体主键自动判断新增或更新。
- *
- * @param entity 实体对象,为 null 或依赖未就绪时返回 null
- * @return merge 后的实体实例(可能是新对象引用)
- */
@Override
- public T save(T entity) {
- if (entity == null || entityManager == null || entityClass == null) {
+ public String getIdFieldName() {
+ return idFieldName;
+ }
+
+ @Override
+ public E save(E entity) {
+ if (entity == null || entityManager == null || poClass == null) {
return null;
}
- T saved = entityManager.merge(entity);
- log.debug("Saved entity: {}", saved);
- return saved;
+ P po = toPo(entity);
+ P savedPo = entityManager.merge(po);
+ log.debug("Saved entity: {}", savedPo);
+ return toEntity(savedPo);
}
- /**
- * 根据主键删除记录。
- *
- * JPA 删除前必须先 find 出受管实体再 remove,无法直接按 ID 删除。
- *
- * @param id 主键值,为 null 时不执行任何操作
- */
@Override
public void removeById(ID id) {
- if (id != null) {
- // JPA 删除需先加载受管实体再 remove
- T entity = findById(id);
- if (entity != null) {
- entityManager.remove(entity);
+ if (id != null && entityManager != null && poClass != null) {
+ P po = entityManager.find(poClass, id);
+ if (po != null) {
+ entityManager.remove(po);
log.debug("Removed entity: id={}", id);
}
}
}
- /**
- * 根据主键查询实体。
- *
- * @param id 主键值,为 null 时返回 null
- * @return 实体对象,未找到时返回 null
- */
@Override
- public T findById(ID id) {
- if (id == null) {
+ public E findById(ID id) {
+ if (id == null || entityManager == null || poClass == null) {
return null;
}
- T entity = entityManager.find(entityClass, id);
- log.debug("Find by id: id={}, found={}", id, entity != null);
- return entity;
+ P po = entityManager.find(poClass, id);
+ log.debug("Find by id: id={}, found={}", id, po != null);
+ return toEntity(po);
}
- /**
- * 根据主键查询(与 findById 等价,语义上用于"读模型")。
- *
- * @param id 主键值
- * @return 实体对象,未找到时返回 null
- */
@Override
- public T queryById(ID id) {
+ public E queryById(ID id) {
return findById(id);
}
- /**
- * 根据主键查询并以 {@link Optional} 包装返回。
- *
- * @param id 主键值
- * @return 包含实体的 Optional,未找到时为 {@link Optional#empty()}
- */
@Override
- public Optional
- * 通过 Criteria API 构建等值条件,取结果集首条;多于一条时仅返回首条。
- *
- * @param condition 查询条件对象,为 null 时返回 null
- * @return 首条匹配记录,无匹配时返回 null
- */
@Override
- public T queryOne(T condition) {
+ public E queryOne(E condition) {
if (condition == null) {
return null;
}
- List
- * 条件为 null 时查询全部;否则按非空字段构建 Criteria 等值条件。
- *
- * @param condition 查询条件对象,可为 null
- * @return 匹配的实体列表,无匹配时返回空列表
- */
@Override
- public List
- * 注意:JPA 不支持原生分页时使用内存分页——先 findAll 取全量结果,
- * 再按 subList 切片返回当前页。该实现适用于中小数据量;大数据量场景
- * 建议用户自定义 Delegate 子类覆盖本方法,使用原生 SQL 分页。
- *
- * @param reqPage 分页请求(页码从 1 开始、每页大小,为 null 时取默认 1/10)
- * @return 分页结果,含当前页、总页数、总条数、当前页记录
- */
@Override
- public ResPage query = cb.createQuery(poClass);
+ query.from(poClass);
- ResPage typedQuery = entityManager.createQuery(query);
+ typedQuery.setFirstResult(pageNum * pageSize);
+ typedQuery.setMaxResults(pageSize);
+
+ pageContent = typedQuery.getResultList().stream()
+ .map(this::toEntity)
+ .collect(Collectors.toList());
+ } else {
+ pageContent = List.of();
+ }
+
+ ResPage query = cb.createQuery(poClass);
+ query.from(poClass);
+ return entityManager.createQuery(query).getResultList().stream()
+ .map(this::toEntity)
+ .collect(Collectors.toList());
}
- /**
- * 通过 Criteria API 按条件等值查询。
- *
- * @param condition 条件对象
- * @return 匹配的实体列表
- */
- private List query = cb.createQuery(poClass);
+ Root root = query.from(poClass);
- // 构建等值 Predicate 数组并拼接到 WHERE 子句
Predicate[] predicates = buildPredicates(cb, root, condition);
if (predicates.length > 0) {
query.where(predicates);
}
- return entityManager.createQuery(query).getResultList();
+ return entityManager.createQuery(query).getResultList().stream()
+ .map(this::toEntity)
+ .collect(Collectors.toList());
}
- /**
- * 反射读取条件对象非空字段,构建等值 {@link Predicate} 数组。
- *
- * @param cb CriteriaBuilder
- * @param root 查询根
- * @param condition 条件对象
- * @return 等值 Predicate 数组
- */
- private Predicate[] buildPredicates(CriteriaBuilder cb, Root root, E condition) {
List query = cb.createQuery(poClass);
+ Root root = query.from(poClass);
+
+ query.where(root.get(idFieldName).in(ids));
+
+ return entityManager.createQuery(query).getResultList().stream()
+ .map(this::toEntity)
+ .collect(Collectors.toList());
}
- /**
- * 按条件统计记录数。
- *
- * 当前实现通过查询结果列表的 size 计数(未走 COUNT 查询),适用于中小数据量。
- *
- * @param condition 条件对象,为 null 时统计全表
- * @return 匹配的记录数
- */
@Override
- public long count(T condition) {
+ public long count(E condition) {
+ if (entityManager == null || poClass == null) {
+ return 0;
+ }
+
+ CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+
if (condition == null) {
- return findAll().size();
+ return executeCountQuery(cb);
}
- return queryList(condition).size();
+
+ CriteriaQuery root = countQuery.from(poClass);
+ countQuery.select(cb.count(root));
+
+ Predicate[] predicates = buildPredicates(cb, root, condition);
+ if (predicates.length > 0) {
+ countQuery.where(predicates);
+ }
+
+ return entityManager.createQuery(countQuery).getSingleResult();
}
- /**
- * 判断是否存在匹配条件的记录。
- *
- * @param condition 条件对象
- * @return 存在返回 true,否则 false
- */
@Override
- public boolean exists(T condition) {
+ public boolean exists(E condition) {
return count(condition) > 0;
}
+
+ protected E toEntity(P po) {
+ if (po == null) {
+ return null;
+ }
+ if (entityClass == null) {
+ return (E) po;
+ }
+ try {
+ E entity = entityClass.getDeclaredConstructor().newInstance();
+ BeanUtils.copyProperties(po, entity);
+ return entity;
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to convert PO to entity", e);
+ }
+ }
+
+ protected P toPo(E entity) {
+ if (entity == null) {
+ return null;
+ }
+ if (poClass == null) {
+ return (P) entity;
+ }
+ try {
+ P po = poClass.getDeclaredConstructor().newInstance();
+ BeanUtils.copyProperties(entity, po);
+ return po;
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to convert entity to PO", e);
+ }
+ }
}
\ No newline at end of file
diff --git a/structure-infra-mongodb-starter/README.md b/structure-infra-mongodb-starter/README.md
index ac262a9..c4b420d 100644
--- a/structure-infra-mongodb-starter/README.md
+++ b/structure-infra-mongodb-starter/README.md
@@ -105,7 +105,7 @@ spring:
1. 检测 Bean 是否为 `MongoRepositoryDelegate` 实例
2. 从 Spring 上下文获取 `MongoTemplate` 并注入
-3. 读取 `@DelegateFor(po = XxxPO.class)` 注解,设置 `entityClass`
+3. 通过泛型解析设置 `entityClass`
### 2. 低代码仓储
@@ -166,14 +166,12 @@ public class UserPO {
}
// 2. 仓储接口
-public interface UserRepository extends Repository
- * 当检测到 MongoDB 相关依赖({@link org.springframework.data.mongodb.core.MongoTemplate})时自动配置,
- * 注册 MongoDB 文档操作所需的核心组件,使其与仓储框架无缝集成。
- *
- * 注册的 Bean:
- *
- * 工作机制:
- *
- * 配置方式:
- *
- * 额外配置:
- *
- * 负责根据 PO 类创建 MongoRepositoryDelegate 实例,通过 MongoTemplate 进行文档操作。
- * 当 RepositoryFacade 需要获取 MongoDB 类型的 RepositoryDelegate 时,会通过此工厂进行创建。
- *
- * @param mongoTemplate MongoDB 操作模板,用于执行增删改查等操作
- * @return MongoDelegateFactory 实例
- */
- @Bean
- @ConditionalOnBean(MongoTemplate.class)
- public MongoDelegateFactory mongoDelegateFactory(MongoTemplate mongoTemplate) {
- return new MongoDelegateFactory(mongoTemplate);
- }
-
- /**
- * 创建 MongoDB 委托 Bean 后处理器
- *
- * 在 Bean 初始化完成后,自动为 MongoRepositoryDelegate 实现类注入 MongoTemplate 和实体类。
- *
- * 处理逻辑:
- * 1. 扫描所有 Bean,筛选出 MongoRepositoryDelegate 的实例
- * 2. 从 Spring 上下文获取 MongoTemplate 并注入到 Delegate 实例中
- * 3. 检查是否存在 {@link cn.structure.infra.annotations.DelegateFor} 注解
- * 4. 将注解中指定的 PO 类设置到 Delegate 实例中
- *
- * @return MongoDelegateBeanPostProcessor 实例
- */
- @Bean
- @ConditionalOnBean(MongoTemplate.class)
- public MongoDelegateBeanPostProcessor mongoDelegateBeanPostProcessor() {
- return new MongoDelegateBeanPostProcessor();
- }
}
diff --git a/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoDelegateBeanPostProcessor.java b/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoDelegateBeanPostProcessor.java
deleted file mode 100644
index f71088f..0000000
--- a/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoDelegateBeanPostProcessor.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package cn.structure.infra.mongodb.repository;
-
-import cn.structure.infra.annotations.DelegateFor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanPostProcessor;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.data.mongodb.core.MongoTemplate;
-
-/**
- * MongoDB RepositoryDelegate 的 BeanPostProcessor,负责为用户自定义 Delegate 子类自动注入 MongoTemplate 与实体类型。
- *
- * 在仓储框架中,业务方可继承 {@link MongoRepositoryDelegate} 实现自定义 Delegate,并通过
- * {@link DelegateFor} 注解声明其服务的 PO 类型。本后处理器在 Bean 初始化完成后:
- *
- * 与 {@link MongoDelegateFactory} 的分工:工厂负责"无自定义 Delegate 时自动创建",
- * 本处理器负责"已有自定义 Delegate 时补齐依赖",二者协同保证 RepositoryFacade 总能拿到可用的 Delegate。
- *
- * @author chuck
- * @version 1.0.1
- * @since 2026/6/28
- */
-@Slf4j
-public class MongoDelegateBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
-
- /** Spring 上下文,用于按类型获取 MongoTemplate */
- private ApplicationContext applicationContext;
-
- /**
- * 注入 Spring 应用上下文,供后续按类型查询 Bean。
- *
- * @param applicationContext Spring 应用上下文
- * @throws BeansException 上下文注入异常
- */
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- /**
- * 在 Bean 初始化完成后,对自定义 MongoRepositoryDelegate 实现类注入 MongoTemplate 与实体类型。
- *
- * 仅当 Bean 是 {@link MongoRepositoryDelegate} 实例时执行注入;MongoTemplate 解析失败仅告警不抛异常。
- *
- * @param bean 待处理的 Bean 实例
- * @param beanName Bean 名称
- * @return 原始 Bean(已注入依赖),未匹配类型时原样返回
- * @throws BeansException 处理过程中的异常
- */
- @SuppressWarnings({"unchecked", "rawtypes"})
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof MongoRepositoryDelegate) {
- MongoRepositoryDelegate delegate = (MongoRepositoryDelegate) bean;
- try {
- // 按类型从容器获取 MongoTemplate 并注入
- MongoTemplate mongoTemplate = applicationContext.getBean(MongoTemplate.class);
- delegate.setMongoTemplate(mongoTemplate);
-
- // 读取 @DelegateFor 注解,识别该 Delegate 服务的 PO 类型并注入
- DelegateFor annotation = bean.getClass().getAnnotation(DelegateFor.class);
- if (annotation != null && annotation.po() != void.class) {
- delegate.setEntityClass(annotation.po());
- }
-
- log.info("Injected MongoTemplate into MongoRepositoryDelegate: {}", beanName);
- } catch (Exception e) {
- log.warn("Failed to inject MongoTemplate into MongoRepositoryDelegate {}: {}", beanName, e.getMessage());
- }
- }
- return bean;
- }
-}
\ No newline at end of file
diff --git a/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoDelegateFactory.java b/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoDelegateFactory.java
deleted file mode 100644
index d7cb15a..0000000
--- a/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoDelegateFactory.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package cn.structure.infra.mongodb.repository;
-
-import cn.structure.infra.repository.RepositoryDelegate;
-import cn.structure.infra.repository.RepositoryDelegateFactory;
-import cn.structure.infra.repository.RepositoryType;
-import org.springframework.data.mongodb.core.MongoTemplate;
-
-/**
- * MongoDB 仓储委托工厂
- *
- * 实现 {@link RepositoryDelegateFactory} SPI,自动创建 {@link MongoRepositoryDelegate} 实例。
- * 在仓储框架中,当 {@code RepositoryFacade} 找不到用户自定义的 Delegate 时,会通过本工厂按 PO 类型
- * 创建默认 Delegate 实例(依赖容器中的 {@link MongoTemplate})。
- *
- * 与 {@link MongoDelegateBeanPostProcessor} 的分工:本工厂负责"无自定义 Delegate 时创建默认实现",
- * BeanPostProcessor 负责"已有自定义子类时补齐依赖"。
- *
- * @author chuck
- * @version 1.0.1
- * @since 2026/6/28
- */
-public class MongoDelegateFactory implements RepositoryDelegateFactory {
-
- /** MongoDB 操作模板,由容器注入并共享给所有 Delegate 实例 */
- private final MongoTemplate mongoTemplate;
-
- /**
- * 构造工厂,注入 MongoTemplate。
- *
- * @param mongoTemplate MongoDB 操作模板
- */
- public MongoDelegateFactory(MongoTemplate mongoTemplate) {
- this.mongoTemplate = mongoTemplate;
- }
-
- /**
- * 返回该工厂支持的仓储类型,用于 SPI 路由匹配。
- *
- * @return 固定返回 {@link RepositoryType#MONGODB}
- */
- @Override
- public RepositoryType getType() {
- return RepositoryType.MONGODB;
- }
-
- /**
- * 为指定 PO 类型创建 {@link MongoRepositoryDelegate} 实例。
- *
- * MongoDB 实现不依赖 Mapper 查找,直接以入参 PO 类型构造 Delegate,因此失败概率较低;
- * 出现异常时返回 null,由上层 RepositoryFacade 继续尝试其他工厂或抛出异常。
- *
- * @param poClass PO 实体类型
- * @param idClass 主键类型(当前实现未使用,保留以匹配 SPI 签名)
- * @return 已注入 MongoTemplate 的 Delegate 实例;构造异常时返回 null
- */
- @Override
- @SuppressWarnings({"unchecked", "rawtypes"})
- public RepositoryDelegate, ?> createDelegate(Class> poClass, Class> idClass) {
- try {
- return new MongoRepositoryDelegate(mongoTemplate, poClass);
- } catch (Exception e) {
- return null;
- }
- }
-}
diff --git a/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoRepositoryDelegate.java b/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoRepositoryDelegate.java
index f1afbbf..a447592 100644
--- a/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoRepositoryDelegate.java
+++ b/structure-infra-mongodb-starter/src/main/java/cn/structure/infra/mongodb/repository/MongoRepositoryDelegate.java
@@ -2,18 +2,23 @@
import cn.structure.common.vo.ReqPage;
import cn.structure.common.vo.ResPage;
+import cn.structure.infra.repository.GenericTypeResolver;
import cn.structure.infra.repository.RepositoryDelegate;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
+import jakarta.persistence.Id;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import java.util.stream.Collectors;
/**
* 基于 MongoDB 的 RepositoryDelegate 适配实现
@@ -30,229 +35,171 @@
* 实现说明:
* 持久化对象类型(MongoDB Document)
* @param
- * 创建后由 {@link MongoDelegateBeanPostProcessor} 通过 setter 注入依赖。
- */
+ protected Class poClass;
+ protected Class ) GenericTypeResolver.resolvePoClass(getClass());
+ this.idClass = (Class
- * 委托给 {@link MongoTemplate#save(Object)},由 MongoDB 依据 _id 自动判断新增或更新。
- *
- * @param entity 实体对象,为 null 时返回 null
- * @return 保存后的实体(与入参同一引用)
- */
@Override
- public T save(T entity) {
+ public E save(E entity) {
if (entity == null) {
return null;
}
- T saved = mongoTemplate.save(entity);
- log.debug("Saved entity: {}", saved);
- return saved;
+ P po = toPo(entity);
+ P savedPo = mongoTemplate.save(po);
+ log.debug("Saved entity: {}", savedPo);
+ return toEntity(savedPo);
}
- /**
- * 根据主键删除文档。
- *
- * @param id 主键值,为 null 时不执行任何操作
- */
@Override
public void removeById(ID id) {
- if (id != null) {
- // 按主键字段构建等值条件并删除
+ if (id != null && poClass != null) {
Query query = new Query(Criteria.where(idFieldName).is(id));
- mongoTemplate.remove(query, entityClass);
+ mongoTemplate.remove(query, poClass);
log.debug("Removed entity: id={}", id);
}
}
- /**
- * 根据主键查询文档。
- *
- * @param id 主键值,为 null 时返回 null
- * @return 实体对象,未找到时返回 null
- */
@Override
- public T findById(ID id) {
- if (id == null) {
+ public E findById(ID id) {
+ if (id == null || poClass == null) {
return null;
}
Query query = new Query(Criteria.where(idFieldName).is(id));
- T entity = mongoTemplate.findOne(query, entityClass);
- log.debug("Find by id: id={}, found={}", id, entity != null);
- return entity;
+ P po = mongoTemplate.findOne(query, poClass);
+ log.debug("Find by id: id={}, found={}", id, po != null);
+ return toEntity(po);
}
- /**
- * 根据主键查询(与 findById 等价,语义上用于"读模型")。
- *
- * @param id 主键值
- * @return 实体对象,未找到时返回 null
- */
@Override
- public T queryById(ID id) {
+ public E queryById(ID id) {
return findById(id);
}
- /**
- * 根据主键查询并以 {@link Optional} 包装返回。
- *
- * @param id 主键值
- * @return 包含实体的 Optional,未找到时为 {@link Optional#empty()}
- */
@Override
- public Optional
- * 通过反射构建 {@link Query},取首条匹配;多于一条时仅返回首条。
- *
- * @param condition 查询条件对象,为 null 时返回 null
- * @return 首条匹配记录,无匹配时返回 null
- */
@Override
- public T queryOne(T condition) {
+ public E queryOne(E condition) {
if (condition == null) {
return null;
}
Query query = buildQuery(condition);
- return mongoTemplate.findOne(query, entityClass);
+ P po = mongoTemplate.findOne(query, poClass);
+ return toEntity(po);
}
- /**
- * 根据条件查询单条记录,并以 {@link Optional} 包装返回。
- *
- * @param condition 查询条件对象
- * @return 包含首条匹配记录的 Optional
- */
@Override
- public Optional
- * 条件为 null 时查询全部;否则按非空字段构建等值 {@link Query}。
- *
- * @param condition 查询条件对象,可为 null
- * @return 匹配的实体列表,无匹配时返回空列表
- */
@Override
- public List
- * 通过 {@link MongoTemplate#count(Query, Class)} 获取总数,
- * 再用 {@link PageRequest} 切片查询当前页记录。
- *
- * @param reqPage 分页请求(页码从 1 开始、每页大小,为 null 时取默认 1/10)
- * @return 分页结果,含当前页、总页数、总条数、当前页记录
- */
@Override
- public ResPage
- *
- *
- *
- *
- *
- *
- * @author chuck
- * @version 1.0.1
- * @since 2026/6/28
- */
@AutoConfiguration
@ConditionalOnClass(name = "org.springframework.data.jpa.repository.JpaRepository")
@EnableJpaRepositories
@EnableTransactionManagement
public class JpaAutoConfiguration {
-
- /**
- * 创建 JPA 仓储委托工厂
- *
- *
- *
- *
- *
- * @return EntityManager 实例,无法解析时返回 null
- */
- private EntityManager getEntityManager() {
- // 1) by name:优先按 "entityManager" 名称获取已注册的容器 Bean
- try {
- Object bean = applicationContext.getBean("entityManager");
- if (bean instanceof EntityManager) {
- return (EntityManager) bean;
- }
- } catch (Exception e) {
- log.debug("entityManager bean not found by name");
- }
-
- // 2) by type → create:通过 EntityManagerFactory 创建新的 EntityManager
- try {
- EntityManagerFactory factory = applicationContext.getBean(EntityManagerFactory.class);
- if (factory != null) {
- return factory.createEntityManager();
- }
- } catch (Exception e) {
- log.debug("EntityManagerFactory bean not found");
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git a/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaDelegateFactory.java b/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaDelegateFactory.java
deleted file mode 100644
index 14ed7bf..0000000
--- a/structure-infra-jpa-starter/src/main/java/cn/structure/infra/jpa/repository/JpaDelegateFactory.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package cn.structure.infra.jpa.repository;
-
-import cn.structure.infra.repository.RepositoryDelegate;
-import cn.structure.infra.repository.RepositoryDelegateFactory;
-import cn.structure.infra.repository.RepositoryType;
-
-import jakarta.persistence.EntityManager;
-
-/**
- * JPA 仓储委托工厂
- *
- *
- *
- *
- *
- *
- *
- *
- *
- * @author chuck
- * @version 1.0.1
- * @since 2026/6/28
- */
@AutoConfiguration
@ConditionalOnClass(name = "org.springframework.data.mongodb.core.MongoTemplate")
@ConditionalOnProperty(prefix = "structure.infra", name = "type", havingValue = "MONGODB", matchIfMissing = true)
@EnableMongoRepositories
public class MongoAutoConfiguration {
-
- /**
- * 创建 MongoDB 仓储委托工厂
- *
- *
- *
*
*
- * @param