1、背景说明       

        项目属于Spring Boot,本身一直都是正常的,由于最近安全活动禁用了Redis的Config命令,导致项目重启报错:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer' defined in class path resource [org/springframework/boot/autoconfigure/session/RedisSessionConfiguration$SpringBootRedisHttpSessionConfiguration.class]: Invocation of init method failed; 
nested exception is org.springframework.data.redis.connection.ClusterCommandExecutionFailureException: ERR config is disabled command; 
nested exception is redis.clients.jedis.exceptions.JedisDataException: ERR config is disabled command; 
nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: ERR config is disabled command; 
nested exception is redis.clients.jedis.exceptions.JedisDataException: ERR config is disabled command

2、分析

        查看RedisHttpSessionConfiguration类源码(如下),发现配置开启keyspace notifications功能的入参:configureRedisAction。ConfigureRedisAction接受注入,默认的来自构造函数中的new ConfigureNotifyKeyspaceEventsAction(),翻看这个类源码(这里就不贴了)发现,这个类用来配置“notify-keyspace-events”功能的,然后在静态内部类EnableRedisKeyspaceNotificationsInitializer中会用到Redis的Config命令,由于Config命令被禁用了,因此就报上述异常了。

        看静态内部类中后处理有个条件if (this.configure != ConfigureRedisAction.NO_OP) ,到这里解决思路很明显了。   

        解决思路就是自己注入ConfigureRedisAction.NO_OP,不要接收默认的ConfigureNotifyKeyspaceEventsAction。ConfigureRedisAction.NO_OP本身不做任何处理。

private ConfigureRedisAction configureRedisAction;

......

public RedisHttpSessionConfiguration() {
        this.redisFlushMode = RedisFlushMode.ON_SAVE;
        this.cleanupCron = "0 * * * * *";
        this.configureRedisAction = new ConfigureNotifyKeyspaceEventsAction();
    }

......

@Autowired(
        required = false
    )
    public void setConfigureRedisAction(ConfigureRedisAction configureRedisAction) {
        this.configureRedisAction = configureRedisAction;
    }

......

@Bean
    public InitializingBean enableRedisKeyspaceNotificationsInitializer() {
        return new RedisHttpSessionConfiguration.EnableRedisKeyspaceNotificationsInitializer(this.redisConnectionFactory, this.configureRedisAction);
    }
......

static class EnableRedisKeyspaceNotificationsInitializer implements InitializingBean {
        private final RedisConnectionFactory connectionFactory;
        private ConfigureRedisAction configure;

        EnableRedisKeyspaceNotificationsInitializer(RedisConnectionFactory connectionFactory, ConfigureRedisAction configure) {
            this.connectionFactory = connectionFactory;
            this.configure = configure;
        }

        public void afterPropertiesSet() throws Exception {
            if (this.configure != ConfigureRedisAction.NO_OP) {
                RedisConnection connection = this.connectionFactory.getConnection();

                try {
                    this.configure.configure(connection);
                } finally {
                    try {
                        connection.close();
                    } catch (Exception var8) {
                        LogFactory.getLog(this.getClass()).error("Error closing RedisConnection", var8);
                    }

                }

            }
        }
    }

 3、解决方法

        注入默认对象ConfigureRedisAction.NO_OP,加个配置项开关,以不变应万变。

package com.abc.test.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.ConfigureRedisAction;

/**
 * 禁用Redis的config命令后:
 * 这里当配置文件redis.disableConfig=true时注入ConfigureRedisAction.NO_OP解决该问题,否则按默认处理
 * @author test
 * @version 1.0
 * @date 2021/12/29 15:44
 */
@Configuration
@ConditionalOnProperty(value = "redis.disableConfig", havingValue = "true")
public class HttpSessionConfig {

    @Bean
    public static ConfigureRedisAction configureRedisAction(){
        return ConfigureRedisAction.NO_OP;
    }
}

时间紧迫,结束!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐