springboot默认是使用基于lettuce的redis客户端,默认情况下LettuceConnectionFactory的shareNativeConnection属性值为true;在springboot的IOC容器之中一个LettuceConnectionFactory最多提供两个共享本地连接,一个给RedisTemplate和StringRedisTemplate的所有操作共用,另外一个给ReactiveRedisTemplate和ReactiveStringRedisTemplate的所有操作共用。

一个对springboot redis框架进行重写,支持lettuce、jedis、连接池、同时连接多个集群、多个redis数据库、开发自定义属性配置的开源SDK:

<dependency>
    <groupId>io.github.mingyang66</groupId>
    <artifactId>emily-spring-boot-redis</artifactId>
    <version>4.3.9</version>
</dependency>

GitHub地址:https://github.com/mingyang66/spring-parent

一、LettuceConnectionFactory连接工厂类默认属性
	//建立Redis连接的client对象
  private @Nullable AbstractRedisClient client;
	private @Nullable LettuceConnectionProvider connectionProvider;
	private @Nullable LettuceConnectionProvider reactiveConnectionProvider;
  //是否校验连接,默认:false
	private boolean validateConnection = false;
  //是否共享本地连接,默认:true
	private boolean shareNativeConnection = true;
  //是否提前初始化共享本地连接,默认:false
	private boolean eagerInitialization = false;
  //通用共享本地连接,默认:null
	private @Nullable SharedConnection<byte[]> connection;
  //基于reactive的通用共享本地连接,默认:null
	private @Nullable SharedConnection<ByteBuffer> reactiveConnection;
二、Redis连接获取统一入口RedisConnectionUtils#doGetConnection
public static RedisConnection doGetConnection(RedisConnectionFactory factory, boolean allowCreate, boolean bind,
			boolean transactionSupport) {
		...
      //入参factory是LettuceConnectionFactory对象,
		RedisConnection connection = fetchConnection(factory);
		...
		return connection;
	}
	private static RedisConnection fetchConnection(RedisConnectionFactory factory) {
    //通过LettuceConnectionFactory对象的getConnection方法获取连接对象
		return factory.getConnection();
	}
三、LettuceConnectionFactory#getConnection连接工厂类方法获取连接对象
	public RedisConnection getConnection() {

		assertInitialized();

		if (isClusterAware()) {
			return getClusterConnection();
		}
		//此处会获取基于lettuce的连接对象
		LettuceConnection connection = doCreateLettuceConnection(getSharedConnection(), connectionProvider, getTimeout(),
				getDatabase());
		connection.setConvertPipelineAndTxResults(convertPipelineAndTxResults);
		return connection;
	}
 // 当前shareNativeConnection为true,则回去获取或者创建本地原生共享连接
	@Nullable
	protected StatefulRedisConnection<byte[], byte[]> getSharedConnection() {
		return shareNativeConnection && !isClusterAware()
				? (StatefulRedisConnection) getOrCreateSharedConnection().getConnection()
				: null;
	}
	// 首先创建一个共享连接对象,此处包含一个真实创建连接对象的connectionProvider对象,实际是StandaloneConnectionProvider
  // 实际的创建原理,我们后面的文章分析
	private SharedConnection<byte[]> getOrCreateSharedConnection() {

		synchronized (this.connectionMonitor) {

			if (this.connection == null) {
				this.connection = new SharedConnection<>(connectionProvider);
			}

			return this.connection;
		}
	}
四、LettuceConnectionFactory.SharedConnection#getConnection创建原生共享本地连接
		// 此方法是所有创建真正的物理连接都要调用的方法入口
    @Nullable
		StatefulConnection<E, E> getConnection() {

			synchronized (this.connectionMonitor) {
        //如果连接不存在,则会创建本地连接
				if (this.connection == null) {
					this.connection = getNativeConnection();
				}
				// 此处是根据属性配置是否需要校验连接有效性,如果需要则会校验,本文不做重点分析
				if (getValidateConnection()) {
					validateConnection();
				}

				return this.connection;
			}
		}
		private StatefulConnection<E, E> getNativeConnection() {
      //此处是创建本地连接的入口,具体是调用LettuceConnectionProvider的子类StandaloneConnectionProvider
			return connectionProvider.getConnection(StatefulConnection.class);
		}
五、StandaloneConnectionProvider#getConnection方法创建本地连接
	@Override
	public <T extends StatefulConnection<?, ?>> T getConnection(Class<T> connectionType) {

		if (connectionType.equals(StatefulRedisSentinelConnection.class)) {
			return connectionType.cast(client.connectSentinel());
		}

		if (connectionType.equals(StatefulRedisPubSubConnection.class)) {
			return connectionType.cast(client.connectPubSub(codec));
		}
		//本地连接是通过此处方法创建,具体是通过client.connect创建
    //此处的client是通过LettuceConnectionFactory的afterPropertiesSet方法初始化的client对象
    //再具体的创建连接过程要进入RedisClient对象中,本文不做进一步分析。
		if (StatefulConnection.class.isAssignableFrom(connectionType)) {

			return connectionType.cast(readFrom.map(it -> this.masterReplicaConnection(redisURISupplier.get(), it))
					.orElseGet(() -> client.connect(codec)));
		}

		throw new UnsupportedOperationException("Connection type " + connectionType + " not supported");
	}
六、共享本地连接是如何实现的

​ 经过上面的源码分析其实结果已经很清楚了,redis的共享本地连接就保存在ioc容器中的LettuceConnectionFactory连接工厂类对象中,有两个属性connection、reactiveConnection,其为通用编程模式和响应式编程分别提供了一个共享本地对象,开发者可以根据个人编程需求通过RedisTemplate等模板对象去LettuceConnectionFactory对象上去取符合要求的共享本地连接。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐