有两种方式: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原理