中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

springboot~SpringData自(zi)定義Repository的(de)正(zheng)確方式(shi)

獲取Spring Data自定義Repository中的實際類型

在Spring Data中(zhong),當您實(shi)現(xian)自(zi)定義Repository時(shi),由(you)于Java類型擦除(chu)的原因(yin),泛型參(can)數T在運行時(shi)確實(shi)會被擦除(chu)為Object類型。不過,有幾種方(fang)法可(ke)以獲取實(shi)際的類型信息。

你想在自定義的 Spring Data Neo4j Repository 接口中通過默認方法獲取泛型 T 的實際類型,這個想法很自然,但遺憾的是,由于 Java 泛型在編譯后的"類型擦除"機制,直接在接口的默認方法中可靠地獲取 T 的實際類型(Class)是非常困難甚至不可行的。

Java 的(de)(de)泛型(xing)(xing)(xing)主要在(zai)編譯(yi)階段提供類型(xing)(xing)(xing)安全(quan)檢查,編譯(yi)后泛型(xing)(xing)(xing)類型(xing)(xing)(xing)信(xin)息(如 T)會被(bei)擦除(除非是(shi)繼(ji)承自泛型(xing)(xing)(xing)父類或實(shi)(shi)現(xian)了(le)泛型(xing)(xing)(xing)接(jie)(jie)口,且這些(xie)泛型(xing)(xing)(xing)類型(xing)(xing)(xing)已被(bei)具體化)。在(zai)你的(de)(de) CustomNeo4jRepository<T, ID> 接(jie)(jie)口中,T 是(shi)一(yi)個類型(xing)(xing)(xing)參數。接(jie)(jie)口的(de)(de)默認方(fang)法(fa)中,無法(fa)直(zhi)接(jie)(jie)獲取實(shi)(shi)現(xian)類所指定的(de)(de) T 的(de)(de)具體類型(xing)(xing)(xing)。

問題描述

直接獲取泛型實際類型的挑戰

Java 的泛(fan)型主要(yao)在編(bian)譯階段提供類型安全檢查,編(bian)譯后泛(fan)型類型信息(如 T)會被(bei)擦除(除非是繼承自泛(fan)型父類或(huo)實現了泛(fan)型接口(kou),且這(zhe)些泛(fan)型類型已被(bei)具體化)。在你的 CustomNeo4jRepository<T, ID> 接口(kou)中,T 是一個類型參數。接口(kou)的默認方法(fa)中,無法(fa)直接獲(huo)取實現類所指(zhi)定的 T 的具體類型。

例如,你希望這樣:

public interface CustomNeo4jRepository<T, ID> {
    
    default Class<T> getEntityType() {
        // 無法直接在此獲取到 UserNode 等具體類型
        // 編譯后 T 會被擦除為 Object
        return ...; 
    }
}

當 UserRepository 繼承 CustomNeo4jRepository<UserNode, Long> 時,JVM 在運(yun)行時看到(dao)的仍然(ran)是(shi) CustomNeo4jRepository<Object, Serializable>,無法感(gan)知(zhi)到(dao) UserNode。

即使嘗試通過反射獲取泛型信息(如 getClass().getGenericInterfaces()),其結果也取決于接口是如何被繼承和代理的。Spring Data 通常會為 Repository 接口創建代理對象,這使得通過反射獲取到的泛型信息很可能是 T 本身(一個 TypeVariable),而非具體的 UserNode 類型,因此難以直接轉換為 Class

問題回顧(為什么難)

  • Java 泛型在運行時會被擦除(type erasure),直接用 T 在運行時無法得到 Class。
  • Spring Data 在創建 Repository 時會用生成的實現類 / 代理類,進一步增加了通過 getClass() 找泛型信息的不穩定性。

先要明確一點

  • 你提到沒有 Neo4jRepositoryFactory,且 Neo4jRepositoryFactoryBean 是 final,這說明你在用的是較新的 SDN 版本(例如 SDN6系列或更高),API 與老版本不同。基于此,不建議嘗試繼承 factory bean 或直接替換內部工廠,而應采用官方推薦的擴展點:repository fragments、repository base class(如果支持)或 AOP/Service 包裝器等。

解決方案[已成功]

  1. 添加自定義的注解@EnableNeo4jCustomRepository,這個注入用來為@EnableNeo4jRepositories注解添加默認值,避免開發人員直接干預它
  2. 為CustomNeo4jRepository接口添加注解@NoRepositoryBean,不讓jpa使用代理建立實現類
  3. 為CustomNeo4jRepository類添加基類SimpleNeo4jRepository,讓它有操作neo4j數據庫的基本能力,它在上面去擴展個性化方法
  4. 開發人員在業務項目中,直接引用@EnableNeo4jCustomRepository注解即可
/**
 * 引入個人性倉儲
 * @author lind
 * @date 2025/9/1 14:57
 * @since 1.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@EnableNeo4jAuditing
@EnableNeo4jRepositories(repositoryBaseClass = CustomNeo4jRepositoryImpl.class)
public @interface EnableNeo4jCustomRepository {
}

/**
 * 個性化接口規范
 * @author lind
 * @date 2025/9/1 14:57
 * @since 1.0.0
 */
@NoRepositoryBean // 不讓jpa使用代理建立實現類
public interface CustomNeo4jRepository<T, ID> {

    /**
     * 根據節點名稱模糊查詢并分頁
     * @param namePattern 名稱模式(如"%知%")
     * @param pageable 分頁信息
     * @return 分頁后的節點列表
     */
    Page<T> findByNameLike(String namePattern, Pageable pageable);
}

/**
 * 個性化接口實現
 * @author lind
 * @date 2025/9/1 14:57
 * @since 1.0.0
 */
public class CustomNeo4jRepositoryImpl<T, ID> extends SimpleNeo4jRepository<T,ID>
        implements CustomNeo4jRepository<T, ID> {

    private final Neo4jOperations neo4jOperations;
    Neo4jEntityInformation<T, ID> entityInformation;
    Class<T> domainType;

    protected CustomNeo4jRepositoryImpl(Neo4jOperations neo4jOperations,
                                        Neo4jEntityInformation<T, ID> entityInformation) {
        super(neo4jOperations,entityInformation);
        this.neo4jOperations = neo4jOperations;
        this.entityInformation = entityInformation;
        this.domainType = entityInformation.getJavaType();
    }


    @Override
    public Page<T> findByNameLike(String namePattern, Pageable pageable) {
        String cypherQuery = "MATCH (n:" + domainType.getSimpleName() +
                ") WHERE n.userName CONTAINS $name RETURN n ORDER BY n.userName SKIP $skip LIMIT $limit";
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("name", namePattern.replace("%", ""));
        parameters.put("skip", pageable.getOffset());
        parameters.put("limit", pageable.getPageSize());

        List<T> results = neo4jOperations.findAll(cypherQuery, parameters, domainType);

        // 獲取總數用于分頁
        String countQuery = "MATCH (n:" + domainType.getSimpleName() + ") WHERE n.name CONTAINS $name RETURN COUNT(n)";
        Long total = neo4jOperations.count(countQuery, parameters);

        return new PageImpl<>(results, pageable, total);
    }
}

@SpringBootApplication
@EnableNeo4jAuditing
@EnableNeo4jCustomRepository
public class NeoApp {
	public static void main(String[] args) {
		SpringApplication.run(NeoApp.class, args);
	}
}

posted @ 2025-09-08 16:57  張占嶺  閱讀(108)  評論(0)    收藏  舉報