当前位置: 首页 > 工具软件 > k-Redis > 使用案例 >

shiro-redis.jar包改造为使用shiro-redis集群

詹钊
2023-12-01

shiro和redis集成的shiro-redis是单个的redis,根据项目需要,把shiro-redis单个的redis改为集群模式,

首先自己新建一个项目:或者打开shiro-redis项目的源码:

原作者下载链接:https://github.com/alexxiyang/shiro-redis.git 原作者现在修改了许多东西,

此处是自己当时派生过来的仓库地址:https://github.com/zhshyong/shiro-redis.git 

下面的改造全是根据自己派生过来的仓库地址代码改造而成

pom.xml文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.crazycake</groupId>
    <artifactId>org.crazycake</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>shiro.redis.cluster</finalName>
        <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>*.xml</exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.7.6.201602180812</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

        </plugins>
    </build>
</project>

首先改造org.crazycake.shiro.RedisManager 类,原来单个redis里面是写死的:

/**
 * Copyright 2017 Inc.
 **/
package org.crazycake.shiro;

import redis.clients.jedis.JedisCluster;

import java.util.TreeSet;

/**
 * @author zhangshaoyong
 */
public class RedisManager {

  private JedisCluster jedisCluster;

  private RedisOperator redisOperator;

  private int expire = 0;

  public RedisOperator getRedisOperator() {
    return redisOperator;
  }

  public void setRedisOperator(RedisOperator redisOperator) {
    this.redisOperator = redisOperator;
  }

  public int getExpire() {
    return expire;
  }

  public void setExpire(int expire) {
    this.expire = expire;
  }

  public JedisCluster getJedisCluster() {
    return jedisCluster;
  }

  public void setJedisCluster(JedisCluster jedisCluster) {
    this.jedisCluster = jedisCluster;
  }

  public RedisManager() {

  }

  /**
   * 初始化方法
   */
  public void init() {

  }

  /**
   * get value from redis
   *
   * @param key
   * @return
   */
  public byte[] get(byte[] key) {
    byte[] value = null;
    value = jedisCluster.get(key);
    return value;
  }

  /**
   * set
   *
   * @param key
   * @param value
   * @return
   */
  public byte[] set(byte[] key, byte[] value) {
    jedisCluster.set(key, value);
    if (this.expire != 0) {
      jedisCluster.expire(key, this.expire);
    }
    return value;
  }

  /**
   * set
   *
   * @param key
   * @param value
   * @param expire
   * @return
   */
  public byte[] set(byte[] key, byte[] value, int expire) {
    jedisCluster.set(key, value);
    if (expire != 0) {
      jedisCluster.expire(key, expire);
    }
    return value;
  }

  /**
   * del
   *
   * @param key
   */
  public void del(byte[] key) {
    jedisCluster.del(key);
  }

  /**
   * flush
   */
  public void flushDB() throws Exception {
    redisOperator.flushDB();
  }

  /**
   * size
   */
  public Long dbSize(String pattern) {
    Long dbSize = 0L;
    TreeSet<String> keys = null;
    try {
      keys = keys(pattern);
    } catch (Exception e) {
      e.printStackTrace();
    }
    dbSize = Long.valueOf(keys.size());
    return dbSize;
  }

  /**
   * keys
   *
   * @param pattern
   * @return
   */
  public TreeSet<String> keys(String pattern) throws Exception {
    TreeSet<String> treeSet = new TreeSet<String>();
    treeSet = redisOperator.keys(pattern);
    return treeSet;
  }

}
 

把单个的改为redis集群,使用了集群:所以其中的keys(String pattern)方法以及flushDB()方法都需要自己去写:故引入了

RedisOperator类:其中就是写了flushDB以及keys(String pattern)方法:内容如下:

/**
 * Copyright 2017 Inc.
 **/
package org.crazycake.shiro;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;

import java.util.*;

/**
 * @author zhangshaoyong
 */
public class RedisOperator implements IRedisOperator {
  public final static Logger logger = LoggerFactory.getLogger(RedisOperator.class);

  private JedisCluster jedisCluster;

  @Override
  public TreeSet<String> keys(String pattern) throws Exception {
    logger.debug("Start getting keys...");
    TreeSet<String> keys = new TreeSet<String>();
    Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
    for(String k : clusterNodes.keySet()){
      logger.debug("Getting keys from: {}", k);
      JedisPool jp = clusterNodes.get(k);
      Jedis connection = jp.getResource();
      try {
        Set<String> set = connection.keys(pattern);
        Iterator it = set.iterator();
        while (it.hasNext()) {
          keys.add((String) it.next());
        }
      } catch(Exception e){
        logger.error("Getting keys error: {}", e);
      } finally{
        logger.debug("Connection closed.");
        connection.close();//用完关闭连接
      }
    }
    logger.debug("Keys gotten!");
    return keys;
  }

  @Override
  public void flushDB() throws Exception {
    logger.debug("Start flushDb keys...");
    Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
    for(String k : clusterNodes.keySet()){
      logger.debug("delete keys from: {}", k);
      JedisPool jp = clusterNodes.get(k);
      Jedis connection = jp.getResource();
      try {
        connection.flushDB();
      } catch(Exception e){
        logger.error("Getting keys error: {}", e);
      } finally{
        logger.debug("Connection closed.");
        connection.close();
      }
    }
    logger.debug("flushDB");
  }

  public JedisCluster getJedisCluster() {
    return jedisCluster;
  }

  public void setJedisCluster(JedisCluster jedisCluster) {
    this.jedisCluster = jedisCluster;
  }
}
 

IRedisOperator接口:

/**
 * Copyright 2017 Inc.
 **/
package org.crazycake.shiro;

import java.util.TreeSet;

/**
 * @author zhangshaoyong
 */
public interface IRedisOperator {
  /**
   * 根据pattern 获取所有的keys
   * @param pattern
   * @return
   */
  TreeSet<String> keys(String pattern) throws Exception;

  /**
   * 删除所有的keys
   */
  void flushDB()throws Exception;
}
 

最后写一个JedisClusterFactory工厂来创建redis集群即可

内容如下:

/**
 * Copyright 2017 Inc.
 **/
package org.crazycake.shiro;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * @author zhangshaoyong
 */
public class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean {

  private Resource addressConfig;
  private String addressKeyPrefix;
  private JedisCluster jedisCluster;
  private Integer timeout;
  private Integer maxRedirections;
  private GenericObjectPoolConfig genericObjectPoolConfig;
  private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$");

  public JedisClusterFactory() {
  }

  public JedisCluster getObject() throws Exception {
    return this.jedisCluster;
  }

  public Class<? extends JedisCluster> getObjectType() {
    return this.jedisCluster != null?this.jedisCluster.getClass():JedisCluster.class;
  }

  public boolean isSingleton() {
    return true;
  }

  private Set<HostAndPort> parseHostAndPort() throws Exception {
    try {
      Properties ex = new Properties();
      ex.load(this.addressConfig.getInputStream());
      HashSet haps = new HashSet();
      Iterator i$ = ex.keySet().iterator();

      while(i$.hasNext()) {
        Object key = i$.next();
        if(((String)key).startsWith(this.addressKeyPrefix)) {
          String val = (String)ex.get(key);
          boolean isIpPort = this.p.matcher(val).matches();
          if(!isIpPort) {
            throw new IllegalArgumentException("ip 或 port 不合法");
          }

          String[] ipAndPort = val.split(":");
          HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1]));
          haps.add(hap);
        }
      }

      return haps;
    } catch (IllegalArgumentException var9) {
      throw var9;
    } catch (Exception var10) {
      throw new Exception("解析 jedis 配置文件失败", var10);
    }
  }

  public void afterPropertiesSet() throws Exception {
    Set haps = this.parseHostAndPort();
    this.jedisCluster = new JedisCluster(haps, this.timeout.intValue(), this.maxRedirections.intValue(), this.genericObjectPoolConfig);
  }

  public void setAddressConfig(Resource addressConfig) {
    this.addressConfig = addressConfig;
  }

  public void setTimeout(int timeout) {
    this.timeout = Integer.valueOf(timeout);
  }

  public void setMaxRedirections(int maxRedirections) {
    this.maxRedirections = Integer.valueOf(maxRedirections);
  }

  public void setAddressKeyPrefix(String addressKeyPrefix) {
    this.addressKeyPrefix = addressKeyPrefix;
  }

  public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) {
    this.genericObjectPoolConfig = genericObjectPoolConfig;
  }

}
 

使用配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- jedis cluster config -->
    <bean name="genericObjectPoolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig" >
        <property name="maxWaitMillis" value="-1" />
        <property name="maxTotal" value="1000" />
        <property name="minIdle" value="8" />
        <property name="maxIdle" value="100" />
    </bean>

    <bean id="jedisCluster" class="org.crazycake.shiro.JedisClusterFactory">
        <property name="addressConfig">
            <value>classpath:/redis-config.properties</value>
        </property>
        <property name="addressKeyPrefix" value="address" />

        <property name="timeout" value="300000"/>
        <property name="maxRedirections" value="6" />
        <property name="genericObjectPoolConfig" ref="genericObjectPoolConfig" />
    </bean>
    <bean id="redisManager" class="org.crazycake.shiro.RedisManager">
        <property name="jedisCluster" ref="jedisCluster"/>
        <property name="redisOperator" ref="redisOperator"/>
        <property name="expire" value="1800"/>
    </bean>
    <bean id="redisOperator" class="org.crazycake.shiro.RedisOperator">
        <property name="jedisCluster" ref="jedisCluster"/>
    </bean>
    <!-- cacheManager -->
    <bean id="redisCacheManager" class="org.crazycake.shiro.RedisCacheManager">
        <property name="redisManager" ref="redisManager" />
    </bean>

    <!--  redisCache  -->
    <bean id="redisCache" class="org.crazycake.shiro.RedisCache">
        <constructor-arg ref="redisManager"></constructor-arg>
    </bean>
</beans>

其中redis-config.properties内容如下:必须遵从此格式(或者自己也能改为自己解析的格式)

address1=127.0.0.1:7000
address2=127.0.0.1:7001
address3=127.0.0.1:7002
address4=127.0.0.1:7003
address5=127.0.0.1:7004
address6=127.0.0.1:7005


和shiro整合时候的配置

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="realm"/>
    <property name="cacheManager" ref="shiroRedisCacheManager"/>
    <property name="sessionManager" ref="sessionManager"/>
  </bean>


 <bean id="shiroRedisCacheManager" class="org.crazycake.shiro.RedisCacheManager">
    <property name="redisManager" ref="redisManager"/>
  </bean>


 <bean id="redisManager" class="org.crazycake.shiro.RedisManager">
    <property name="jedisCluster" ref="jedisCluster"/>
    <property name="redisOperator" ref="redisOperator"/>
    <property name="expire" value="180000"/>
  </bean>


  <bean id="jedisCluster" class="org.crazycake.shiro.JedisClusterFactory">
    <property name="addressConfig" value="classpath:/shiro-redis.properties"/>
    <property name="addressKeyPrefix" value="address"/>
    <property name="timeout" value="300000"/>
    <property name="maxRedirections" value="6"/>
    <property name="genericObjectPoolConfig" ref="genericObjectPoolConfig"/>
  </bean>
  
  <bean id="redisOperator" class="org.crazycake.shiro.RedisOperator">
    <property name="jedisCluster" ref="jedisCluster"/>

  </bean>


项目完整地址:https://github.com/zhshyong/shiro-redis-cluster.git

如有不对之处:请大佬们指出,

 类似资料: