javaspringspring-dataspring-data-redisapache-commons-pool

Error trying to wire a Lettuce Connection Factory


I'm trying to setup a connection factory for my redis client (lettuce client version: 2.3.3) using Spring Data Redis (version.: 1.1.x) but I'm having some troubles while wiring everything together.

Here's my configuration: application-context-redis.xml

<bean id="lettuceConnectionFactory"
      class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
    <constructor-arg index="0" ref="redisPool"/>
</bean>

<bean id="redisPool"
      class="org.springframework.data.redis.connection.lettuce.DefaultLettucePool">
        <constructor-arg index="0" value="${redis.host}" />
        <constructor-arg index="1" value="${redis.port}"/>
        <constructor-arg index="2" ref="#{redisPoolConfig.Config}"/>
</bean>

<bean id="redisPoolConfig" class="org.apache.commons.pool.impl.GenericObjectPool"
      p:maxActive="${redis.maxActive}"
      p:maxIdle="${redis.maxIdle}"
      p:minIdle="${redis.minIdle}"
      p:maxWait="${redis.maxWait}"
      p:testOnBorrow="${redis.testOnBorrow}"
      p:testOnReturn="${redis.testOnReturn}"
      p:testWhileIdle="${redis.testWhileIdle}"
      p:whenExhaustedAction="${redis.whenExhaustedAction}"
      p:timeBetweenEvictionRunsMillis="${redis.timeBetweenEvictionRunsMillis}"
      p:numTestsPerEvictionRun="${redis.numTestsPerEvictionRun}"
      p:softMinEvictableIdleTimeMillis="${redis.softMinEvictableIdleTimeMillis}"
      p:minEvictableIdleTimeMillis="${redis.minEvictableIdleTimeMillis}"/>
/>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
      p:connectionFactory-ref="lettuceConnectionFactory"/>

This is the constructor signature of the redisPool bean:

public DefaultLettucePool(String hostName, int port, Config poolConfig) {
        this.hostName = hostName;
        this.port = port;
        this.poolConfig = poolConfig;
}

The poolConfig property is an public inner static class: org.apache.commons.pool.impl.GenericObjectPool.Config

Since the Config property is a static inner class (see here) and does NOT contain a getter method I'm having a hard time trying to inject it to the redisPool bean.

This is the error that I'm getting:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisPool' defined in class path resource [application-context-redis.xml]: Cannot resolve reference to bean '#{redisPoolConfig.Config}' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 16): Field or property 'Config' cannot be found on object of type 'org.apache.commons.pool.impl.GenericObjectPool'
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:615)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:148)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1045)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:949)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323)
    ... 72 more
Caused by: org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 16): Field or property 'Config' cannot be found on object of type 'org.apache.commons.pool.impl.GenericObjectPool'
    at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:142)
    at org.springframework.beans.factory.support.AbstractBeanFactory.evaluateBeanDefinitionString(AbstractBeanFactory.java:1312)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.evaluate(BeanDefinitionValueResolver.java:225)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:312)
    ... 84 more

Solution

  • Spring Data Redis comes with the handy PoolConfig wrapper for org.apache.commons.pool.impl.GenericObjectPool.Config that basically allows you to get around the issue you described above.

    <bean id="lettuceConnectionFactory "
      class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
      <constructor-arg index="0" ref="lettucePool" />
    </bean>
    
    <bean id="lettucePool" class="org.springframework.data.redis.connection.lettuce.DefaultLettucePool">
      <property name="hostName" value="${redis.host}" />
      <property name="port" value="${redis.port}" />
      <property name="poolConfig" ref="lettucePoolConfiguration" />
    </bean> 
    
    <bean id="lettucePoolConfiguration" class="org.springframework.data.redis.connection.PoolConfig">
      <property name="maxIdle" value="${redis.maxIdle}" />
      <property name="maxActive" val...
    </bean>