RunJettyRun 插件使用(spring-data-redis/jedis-2.7.2不兼容)

当使用Spring Data Redis 1.5.0.RELEASE与Jedis 2.7.2及2.7.3时,由于版本不兼容导致NullPointerException。文章分析了错误原因并提出了解决方案。

在Eclipse的RunJettyRun(jetty 7.6.8.v20121106)使用jetty时,在项目中使用到了spring-data-redis-1.5.0.RELEASE.jar、jedis-2.7.2.jar、jedis-2.7.3.jar,于是如以下代码方式访问Redis时:

 

private static RedisTemplate<String, Object> redisTemplate = ...;
redisTemplate.opsForHash().put(CACHE_NAME + key, hashKey, value);

 就会出现如下错误:

 

 

java.lang.ExceptionInInitializerError
	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:252)
	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:58)
	at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:128)
	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:91)
	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:78)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:178)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)
	at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:86)
	at org.springframework.data.redis.core.DefaultHashOperations.put(DefaultHashOperations.java:169)

.........

java.lang.NullPointerException
	at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:455)
	at org.springframework.data.redis.connection.jedis.JedisConnection.<clinit>(JedisConnection.java:108)
	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:252)
	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:58)
	at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:128)
	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:91)
	at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:78)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:178)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)
	at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:86)
	at org.springframework.data.redis.core.DefaultHashOperations.put(DefaultHashOperations.java:169)

 

 

查源码时发现在进行spring-data-redis-1.5.0.RELEASE.jar包下的JedisConnection类中静态块执行的时候失败报出NullPointerException,源码如下所示:

 

static {
		CLIENT_FIELD = ReflectionUtils.findField(BinaryJedis.class, "client", Client.class);
		ReflectionUtils.makeAccessible(CLIENT_FIELD);
		SEND_COMMAND = ReflectionUtils.findMethod(Connection.class, "sendCommand", new Class[] { Command.class,
				byte[][].class });
		ReflectionUtils.makeAccessible(SEND_COMMAND);
		GET_RESPONSE = ReflectionUtils.findMethod(Queable.class, "getResponse", Builder.class);
		ReflectionUtils.makeAccessible(GET_RESPONSE);
	}

 发现在反射获取Connection的sendCommand方法授权时,出现错误,通过查源码发现问题出现在了jedis-2.7.3.jar、jedis-2.7.2.jar 中的Connection的sendCommand的方法,2.7.2对该方法的Command参数进行了升级,与jedis-2.7.3又将2.7.2的改进还原了,从而不兼容导致初始化错误的出现。

 

其中jedis-2.7.3.jar的 Connection源码如下所示:

 

protected Connection sendCommand(final Command cmd, final String... args) {
		final byte[][] bargs = new byte[args.length][];
		for (int i = 0; i < args.length; i++) {
			bargs[i] = SafeEncoder.encode(args[i]);
		}
		return sendCommand(cmd, bargs);
    }
	public static enum Command {
		PING,.....;

		public final byte[] raw;

		Command() {
			raw = SafeEncoder.encode(this.name());
		}
    }

 

 

其中jedis-2.7.2.jar的 Connection源码如下所示:

 

 protected Connection sendCommand(final ProtocolCommand cmd, final String... args) {
		final byte[][] bargs = new byte[args.length][];
		for (int i = 0; i < args.length; i++) {
		  bargs[i] = SafeEncoder.encode(args[i]);
		}
		return sendCommand(cmd, bargs);
	}
	public static enum Command implements ProtocolCommand {
		PING,..... ERGE;

		private final byte[] raw;

		Command() {
		  raw = SafeEncoder.encode(this.name());
		}

		@Override
		public byte[] getRaw() {
		  return raw;
		}
  }

 

 

 

先说解决办法将spring-data-redis升级到spring-data-redis-1.6.0.RELEASE.jar,其中JedisConnection的静态块如下所示:

 

static {

		CLIENT_FIELD = ReflectionUtils.findField(BinaryJedis.class, "client", Client.class);
		ReflectionUtils.makeAccessible(CLIENT_FIELD);

		try {
			Class<?> commandType = ClassUtils.isPresent("redis.clients.jedis.ProtocolCommand", null) ? ClassUtils.forName(
					"redis.clients.jedis.ProtocolCommand", null) : ClassUtils.forName("redis.clients.jedis.Protocol$Command",
					null);

			SEND_COMMAND = ReflectionUtils.findMethod(Connection.class, "sendCommand", new Class[] { commandType,
					byte[][].class });
		} catch (Exception e) {
			throw new NoClassDefFoundError(
					"Could not find required flavor of command required by 'redis.clients.jedis.Connection#sendCommand'.");
		}

		ReflectionUtils.makeAccessible(SEND_COMMAND);

		GET_RESPONSE = ReflectionUtils.findMethod(Queable.class, "getResponse", Builder.class);
		ReflectionUtils.makeAccessible(GET_RESPONSE);
	}

 关键一点在于反射调用sendCommand方法时对方法的参数进行了类型判断从而防止了错误的产生。

 

 

注:经猜测最终原因可能是jetty在进行类实例化时使用的jedis-2.7.2.jar但是在真正调用时却使用的jedis-2.7.3.jar从而导致错误的产生!

 

 

 

<think>好的,我现在需要解决用户关于在Spring Data Redis 2.7.2中配置Jedis连接池和日志打印设置的问题。首先,我需要回忆一下Spring Data RedisJedis的关系。根据用户提供的引用内容,Spring Data Redis是对Redis客户端的封装,而Jedis是其中一个实现方式。用户提到他们需要配置连接池,这可能涉及到设置连接池的参数,比如最大连接数、最小空闲连接等。 接下来,我需要确定在Spring Boot项目中如何配置这些参数。通常,Spring Boot通过application.properties或application.yml文件进行配置。对于Jedis连接池,相关的配置项可能包括spring.redis.jedis.pool下的各个属性,比如max-active、max-idle、min-idle等。记得要检查Spring Data Redis 2.7.2对应的配置项名称是否与最新版本一致,可能需要查阅相关文档确认。 然后是关于日志打印的部分。用户可能希望看到Jedis或连接池的详细日志,以便调试或监控。这需要配置日志框架,比如Logback或Log4j2,设置相应的日志级别。通常,将org.springframework.data.redis的日志级别设为DEBUG或TRACE可以输出更多信息。另外,可能需要单独设置Jedis的日志级别,比如redis.clients.jedis。 还需要考虑是否需要配置连接池的健康检查或其它高级参数,比如连接超时时间、测试连接有效性的配置等。这些参数可能影响连接池的稳定性和性能。 现在需要整合这些信息,确保步骤清晰,配置示例正确。可能需要提供一个配置类的代码示例,比如使用@Configuration注解的类,并通过@Bean定义JedisConnectionFactory,同时设置连接池参数。同时,在application.properties中给出具体的属性配置。 另外,用户提供的引用中提到连接池的创建和Spring Data Redis使用,需要确保配置正确,使得Spring Data Redis使用Jedis作为客户端,并且正确初始化连接池。还要注意版本兼容性,Spring Data Redis 2.7.2对应的Jedis版本是否匹配,避免出现版本冲突。 最后,关于日志打印的设置,除了配置日志级别外,可能还需要在配置文件中指定日志框架的配置文件,比如logback-spring.xml,并在其中设置相关包的日志级别。需要提醒用户根据实际使用的日志框架进行调整。 总结步骤应该是:配置连接池参数、配置日志级别、验证配置是否正确。同时,需要确保示例代码中的配置项名称正确,比如max-active在Spring Boot中可能对应的是max-active还是maxActive,需要注意大小写和格式问题,避免配置不生效。</think>在Spring Data Redis 2.7.2中配置Jedis连接池和日志打印需要以下步骤: ### 一、Jedis连接池配置 1. **基础配置** 在`application.properties`中添加以下参数: ```properties # Redis服务器地址 spring.redis.host=127.0.0.1 spring.redis.port=6379 # 连接池配置 spring.redis.jedis.pool.max-active=8 spring.redis.jedis.pool.max-idle=8 spring.redis.jedis.pool.min-idle=2 spring.redis.jedis.pool.max-wait=2000ms spring.redis.timeout=5000ms ``` 2. **高级配置(可选)** 可通过自定义`JedisConnectionFactory`实现更精细控制: ```java @Configuration public class RedisConfig { @Bean public JedisConnectionFactory jedisConnectionFactory() { RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("127.0.0.1", 6379); JedisClientConfiguration clientConfig = JedisClientConfiguration.builder() .usePooling() .poolConfig(jedisPoolConfig()) .build(); return new JedisConnectionFactory(config, clientConfig); } @Bean public JedisPoolConfig jedisPoolConfig() { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(8); poolConfig.setMaxIdle(8); poolConfig.setMinIdle(2); poolConfig.setMaxWait(Duration.ofMillis(2000)); poolConfig.setTestOnBorrow(true); // 借出连接时校验有效性 return poolConfig; } } ``` ### 二、日志打印配置 1. **日志级别设置** 在`application.properties`中添加: ```properties # Spring Data Redis日志 logging.level.org.springframework.data.redis=DEBUG # Jedis客户端日志 logging.level.redis.clients.jedis=TRACE # 连接池日志 logging.level.org.apache.commons.pool2=DEBUG ``` 2. **日志格式优化** 建议在`logback-spring.xml`中配置详细格式: ```xml <configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="org.springframework.data.redis" level="DEBUG"/> <logger name="redis.clients.jedis" level="TRACE"/> <root level="INFO"> <appender-ref ref="CONSOLE"/> </root> </configuration> ``` ### 三、验证配置 1. 通过`RedisTemplate`执行命令观察日志输出 2. 使用`JMX`或监控工具查看连接池状态 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值