`
xugangqiang
  • 浏览: 7780 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

读写分离的java redis 接口

阅读更多

 目的:为了spring上下文添加读写分离的接口,可以在启动后自动注入redis只读接口或可读写接口

 

1. 定义一个相关的functional interface - 在spring boot的启动类里面要用到(@EnableDynamicKeyValueServiceCreation)

@Retention(value = RetentionPolicy.RUNTIME)

@Import(KeyValueServiceRegister.class)

public @interface EnableDynamicKeyValueServiceCreation {

}

2. 定义只读接口和可读写接口
public interface KeyValueReadService { String get(String key); ...}

public interface KeyValueReadWriteService extends KeyValueReadService { void set(String key, String value); ..}

 

3. 实现类

public class RedisConfigInfo {

    private String hostName;

    private int port;

    private String password;

    private JedisPoolConfig poolConfig;

}

 

public abstract class AbstractRedisOperation {

    private final JedisPool jedisPool;

    public AbstractRedisOperation (RedisConfigInfo info) { jedisPool = ...;}

}

 

public class RedisReadServiceImpl extends AbstractRedisOperation implements KeyValueReadService {

 

    public RedisReadServiceImpl(RedisConfigInfo temp) {

        super(temp);

    }

 

    @Override

    public String get(String key) {

        return stringValueOps.get(key);

    }

}

 

4. 通过spring去获取redis的配置信息

@Component

public class KeyValueServiceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {

 

    private static Logger logger = LoggerFactory.getLogger(KeyValueServiceRegister.class);

 

    private Map<String, BeanDefinition> beanDefinitionMap = null;

 

    @Override

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,

            BeanDefinitionRegistry registry) {

        if (beanDefinitionMap == null || beanDefinitionMap.isEmpty()) {

            logger.warn("beanDefinitions is empty");

            return;

        }

        String beanName;

        BeanDefinition beanDefinition;

        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {

            beanName = entry.getKey();

            beanDefinition = entry.getValue();

            registry.registerBeanDefinition(beanName, beanDefinition);

        }

 

    }

 

    @SuppressWarnings("rawtypes")

    @Override

    public void setEnvironment(Environment environment) {

        String prefix = environment.getProperty("prefix.keyvalue.cache", "kv.");

 

        Properties props = new Properties();

        MutablePropertySources propSrcs = ((AbstractEnvironment) environment).getPropertySources();

        StreamSupport.stream(propSrcs.spliterator(), false)

                .filter(ps -> ps instanceof EnumerablePropertySource)

                .map(ps -> ((EnumerablePropertySource) ps).getPropertyNames())

                .flatMap(Arrays::<String>stream).filter(name -> name.startsWith(prefix)).forEach(

                        propName -> props.setProperty(propName, environment.getProperty(propName)));

        

        beanDefinitionMap = Collections

                .unmodifiableMap(KeyValueServiceHelper.buildBeanDefinitionMap(props));

    }

 

}

 

5. 根据配置信息构建bean

public class KeyValueServiceHelper {

 

    private static final String POSFIX_READ = ".r";

 

    private static final String POSFIX_WRITE = ".w";

 

    public static final Map<String, Properties> buildDataSourceMap(Properties prop) {

        if (prop == null || prop.isEmpty()) {

            return Collections.emptyMap();

        }

        Map<String, Properties> result = new HashMap<>();

        Set<String> keys = prop.stringPropertyNames();

        Properties temp;

        String dsName;

        for (String key : keys) {

            dsName = key;

            if (!isKeyValueServiceBeanName(key)) {

                dsName = removePosfix(key);

            }

            temp = result.get(dsName);

            if (temp == null) {

                temp = new Properties();

                result.put(dsName, temp);

            }

            temp.setProperty(key, prop.getProperty(key));

        }

        return result;

    }

 

    public static final boolean isKeyValueServiceBeanName(String str) {

        if (StringUtils.isBlank(str)) {

            return false;

        }

        return str.endsWith(POSFIX_READ) || str.endsWith(POSFIX_WRITE);

    }

 

    public static final String removePosfix(String str) {

        if (StringUtils.isBlank(str)) {

            return str;

        }

        int idx = str.lastIndexOf(".");

        if (idx == -1) {

            return str;

        }

        return str.substring(0, idx);

    }

 

    public static final String resolveBeanClassName(final String beanName,

            final String connectionStr) {

        if (StringUtils.isBlank(beanName)) {

            throw new IllegalArgumentException("bean name is blank");

        }

 

        if (StringUtils.isBlank(connectionStr)) {

            throw new IllegalArgumentException("connectionStr is blank");

        }

 

        if (!RedisConnectionHelper.isRedisConnectionString(connectionStr)) {

            throw new IllegalArgumentException("connectionStr is invalid");

        }

 

        if (beanName.endsWith(POSFIX_READ)) {

            return RedisReadServiceImpl.class.getName();

        }

        if (beanName.endsWith(POSFIX_WRITE)) {

            return RedisReadWriteServiceImpl.class.getName();

        }

        throw new IllegalArgumentException("beanName is invalid,should end with '.r' or '.w'");

    }

 

    public static final Map<String, BeanDefinition> buildBeanDefinitionMap(Properties props) {

        Map<String, Properties> cacheSources = buildDataSourceMap(props);

        if (cacheSources == null || cacheSources.isEmpty()) {

            return Collections.emptyMap();

        }

        BeanDefinition def;

        String beanName;

        String connectionStr;

        String beanClassName;

        Properties prop;

        RedisConfigInfo info;

        Map<String, BeanDefinition> beanMap =

                new HashMap<String, BeanDefinition>(cacheSources.size());

        for (Map.Entry<String, Properties> entry : cacheSources.entrySet()) {

            beanName = entry.getKey();

            prop = entry.getValue();

            connectionStr = prop.getProperty(beanName);

            if (!RedisConnectionHelper.isRedisConnectionString(connectionStr)) {

                continue;

            }

            info = RedisConnectionHelper.parseRedisConfigInfo(prop, beanName);

 

            def = new GenericBeanDefinition();

            beanClassName = KeyValueServiceHelper.resolveBeanClassName(beanName, connectionStr);

            def.setBeanClassName(beanClassName);

 

            def.getConstructorArgumentValues().addGenericArgumentValue(info);

            beanMap.put(beanName, def);

        }

        return beanMap;

    }

}

 

6. 如何使用

a. 在SpringBoot的启动类里面加上@EnableDynamicKeyValueServiceCreation

b. 配置文件里面加上读写分离的redis的配置信息 - 读的是.r结尾,可写的是.w结尾

c. 在需要只读redis的service里面, 直接注入(@KeyValueReadService (name=**.r)
d. 在需要读写redis的service里面, 直接注入(@KeyValueReadService (name=**.w)

 

0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics