saas化:redis多租户逻辑隔离实现

思路

​ 通过租户id前缀对redis数据进行逻辑隔离。具体通过代理模式,增强RedisConnection的执行方法,对参数key进行租户ID拼接处理。无侵入,不影响生产代码。

实现步骤

1 编写RedisConnection的静态代理类(需要代理的方法太多了,静态代理易读性好)

``

public class RedisTenantProxy implements RedisConnection {
    private final RedisConnection redisConnection;

    public RedisTenantProxy(RedisConnection redisConnection){
        this.redisConnection=redisConnection;
    }

    @Override
    public void close() throws DataAccessException {
            //do something
            redisConnection.close();
            //do something 
    }
 ...
}
2 编写RedisConnectionFactory的代理类,增强其getConnection方法,返回代理连接类

``

public class RedisConntectionFactoryProxy implements InvocationHandler {

    private final RedisConnectionFactory redisConnectionFactory;

    public RedisConntectionFactoryProxy(RedisConnectionFactory redisConnectionFactory) {
        this.redisConnectionFactory = redisConnectionFactory;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RedisConnection result = (RedisConnection) method.invoke(redisConnectionFactory, args);
        if ("getConnection".equals(method.getName())) {
            result=new RedisTenantProxy(result);
        }
        return result;
    }
}
3 编写RedisConfiguration类,在将RedisTemplate注入容器的方法中,设置RedisConnectionFactory的代理类

``

@Configuration
@EnableCaching
public class RedisConfiguration extends CachingConfigurerSupport {
   /**
    * generator key generator.
    *
    * @return the key generator
    */
   @Bean
   public KeyGenerator keyGenerator() {
      return (target, method, params) -> {
         StringBuilder sb = new StringBuilder();
         sb.append(target.getClass().getName());
         sb.append(method.getName());
         for (Object obj : params) {
            sb.append(obj.toString());
         }
         return sb.toString();
      };

   }

   /**
    * Cache manager cache manager.
    *
    * @param redisTemplate the redis template
    *
    * @return the cache manager
    */
   @Bean
   public CacheManager cacheManager(RedisTemplate redisTemplate) {
      return new RedisCacheManager(redisTemplate);
   }

   @Bean
   public StringRedisSerializer stringRedisSerializer() {
      return new StringRedisSerializer();
   }

   @Bean("redisTemplate")
   public RedisTemplate redisTemplate(RedisConnectionFactory factory) {

      RedisTemplate template = new RedisTemplate<>();
      Class aClass = factory.getClass();
      Class[] interfaces = aClass.getInterfaces();
      RedisConnectionFactory factoryProxy = (RedisConnectionFactory)Proxy.newProxyInstance(aClass.getClassLoader(), interfaces, new RedisConntectionFactoryProxy(factory));

      template.setConnectionFactory(factoryProxy);
      Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
      ObjectMapper om = new ObjectMapper();
      om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
      om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
      jackson2JsonRedisSerializer.setObjectMapper(om);
      template.setValueSerializer(jackson2JsonRedisSerializer);
      template.setKeySerializer(stringRedisSerializer());
      template.afterPropertiesSet();
      return template;
   }
}
 
  

4 把上面的类@ComponentScan的工作范围

``

//在启动类加上注解
@ComponentScan(basePackages = {"包路径"})

优缺点分析

​ 优点:统一入口拦截,代码侵入性小,代码结构清晰明了

​ 缺点:侵入了RedisConfigration类,如果以前已经编写了redisConfiguration类,会有改动

你可能感兴趣的:(redis,java,代理模式,架构)