springboot 集成向量数据库milvus==>1.bean 注入 2.milvus 连接池注入

发布于:2025-03-06 ⋅ 阅读:(18) ⋅ 点赞:(0)

有两种方式:1.普通bean 注入 2.milvus 连接池注入
1.普通bean 注入

import io.milvus.pool.MilvusClientV2Pool;
import io.milvus.pool.PoolConfig;
import io.milvus.v2.client.ConnectConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
@Slf4j
public class MilvusConfig {
    @Value("${milvus.url}")
    private String url; //milvus所在服务器地址
    @Value("${milvus.userName}")
    private String userName; //milvus端口
    @Value("${milvus.password}")
    private String password; //milvus端口

    @Bean
    public MilvusClientV2 milvusServiceClient() throws ClassNotFoundException, NoSuchMethodException {
        ConnectConfig connectConfig = ConnectConfig.builder()
                .uri(url)
                .token(userName + ":" + password)
                .build();

        PoolConfig poolConfig = PoolConfig.builder()
                .maxIdlePerKey(10) // max idle clients per key
                .maxTotalPerKey(20) // max total(idle + active) clients per key
                .maxTotal(100) // max total clients for all keys
                .maxBlockWaitDuration(Duration.ofSeconds(5L)) // getClient() will wait 5 seconds if no idle client available
                .minEvictableIdleDuration(Duration.ofSeconds(10L)) // if number of idle clients is larger than maxIdlePerKey, redundant idle clients will be evicted after 10 seconds
                .build();
        return new MilvusClientV2(connectConfig);
    }}

直接引入依赖会出现

```c
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;CLjava/lang/Object;)V
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1054) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) ~[spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
          MilvusClientV2 client = new MilvusClientV2(connectConfig);

需要引入com.google.guava的包,我个人感觉是高版本的包,milvus 官方提供的依赖版本经常缺方法,下面的也一样

 <!--milvus-->
        <dependency>
            <groupId>io.milvus</groupId>
            <artifactId>milvus-sdk-java</artifactId>
            <version>2.4.9</version>
            <exclusions>
                <exclusion>
                    <artifactId>guava</artifactId>
                    <groupId>com.google.guava</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>26.0-jre</version>
            <scope>compile</scope>
        </dependency>

2.milvus 连接池注入

import io.milvus.pool.MilvusClientV2Pool;
import io.milvus.pool.PoolConfig;
import io.milvus.v2.client.ConnectConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
@Slf4j
public class MilvusConfig {
    @Value("${milvus.url}")
    private String url; //milvus所在服务器地址
    @Value("${milvus.userName}")
    private String userName; //milvus端口
    @Value("${milvus.password}")
    private String password; //milvus端口


    @Bean
    public MilvusClientV2Pool milvusClientPool() {

        ConnectConfig config = ConnectConfig.builder()
                .uri(url)
                .token(userName + ":" + password)
                .build();

        PoolConfig poolConfig = PoolConfig.builder()
                .maxIdlePerKey(10) // 每个key最大空闲客户端数
                .maxTotalPerKey(20) // 每个key最大总客户端数(空闲+活跃)
                .maxTotal(100) // 所有key的最大总客户端数
                .maxBlockWaitDuration(Duration.ofSeconds(5L)) // 如果没有空闲客户端,getClient()将等待5秒
                .minEvictableIdleDuration(Duration.ofSeconds(10L))  // 如果空闲客户端数超过maxIdlePerKey,多余的空闲客户端将在10秒后被清除
                .build();
        final MilvusClientV2Pool milvusClientV2Pool;
        try {
            milvusClientV2Pool = new MilvusClientV2Pool(poolConfig, config);
            log.info("---------------milvus 线程池连接成功----------");
        } catch (ClassNotFoundException e) {
            log.error("---------------milvus 连接失败----------");
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        return milvusClientV2Pool;
    }
}

        ConnectConfig connectConfig = ConnectConfig.builder()
                .uri("http://xxxx")
                .dbName("xxx")
                .build();
        log.info("MilvusClientV2.class.getName():{}",MilvusClientV2.class.getName());
        MilvusClientV2 client = null;
        try {
            client = milvusClientPool.getClient("select");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            milvusClientPool.returnClient("select", client);
        }
        final ListCollectionsResp listCollectionsResp = client.listCollections();
        System.out.println("totalActiveClientNumber:" + listCollectionsResp.getCollectionNames());
        final int totalActiveClientNumber = milvusClientPool.getTotalActiveClientNumber();
        log.info("totalActiveClientNumber:{}", totalActiveClientNumber);

在这里插入图片描述

报错

Correct the classpath of your application so that it contains a single, compatible version of org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig

新增依赖commons-pool2,问题解决

 <!--milvus-->
        <dependency>
            <groupId>io.milvus</groupId>
            <artifactId>milvus-sdk-java</artifactId>
            <version>2.4.9</version>
            <exclusions>
                <exclusion>
                    <artifactId>guava</artifactId>
                    <groupId>com.google.guava</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>26.0-jre</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.11.1</version>
        </dependency>
   // 传统Bean注入(单例模式)
   @Bean
   public MilvusClientV2 singleClient() {
       return new MilvusClientV2(...); // 整个应用生命周期只创建1次
   }

   // 连接池模式
   MilvusClientV2 client = pool.getClient(key); // 可能触发新连接创建,但后续请求复用已有连

两者的差异

连接池中的对象(如MilvusClientV2)是池化的资源,而Spring管理的Bean(如连接池实例本身)通常是单例的。
连接池Bean负责管理内部连接对象的生命周期,这些连接对象按需创建和复用,而Bean本身只创建一次。

需要进一步对比两者的对象创建逻辑。单例Bean在应用启动时创建一次,之后每次注入都是同一个实例。
而连接池在第一次获取客户端时创建新连接,但之后会复用,直到达到maxIdlePerKey限制。如果配置合理,连接池可以减少实际的对象创建次数,尤其是在高并发场景下。

最后,总结连接池的优势:通过复用连接对象,减少系统开销,尤其在频繁请求时,避免重复创建和销毁资源。而单例Bean注入确保连接池本身只创建一次,两者结合既保证了资源的高效管理,又遵循了Spring的依赖注入最佳实践。

commons-pool2 线程池 getClient原理
在这里插入图片描述
在这里插入图片描述