Java使用reids,以及redis与shiro集成

页面导航:首页 > 软件编程 > Java编程 > Java使用reids,以及redis与shiro集成

Java使用reids,以及redis与shiro集成

来源: 作者: 时间:2016-01-18 15:52 【

什么是redis:redis是一个key-value存储系统。和Memcached类,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据
什么是redis:redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。(我也是百度的,个人理解reids就是个比较轻量级的key——value模式的,这个数据库的存储性能很好,可以用来代替缓存实现的很多功能。而且这个redis数据库是第三方独立的服务,可以用在负载均衡情况下多个服务器,多个web容器之间公用数据的缓存。) 要使用reids,首先可以到官网reids的jar包和redis。 然后把redis的jar包导入到项目中。 \ 我用的版本是2.1.0. 系统是32位的,所以我解压了32位的redis服务。 \
打开以后使用里面的redis-servier。exe来启动redis服务。启动后的结果如下图所示 \


package org.calonlan.security.component;

import java.util.Iterator;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author Administrator
 *         redismanager主要用来给用户提供一个设计完备的,通过jedis的jar包来管理redis内存数据库的各种方法
 */
public class RedisManager {

	// ip和port属性都定义在了properties文件中,这里通过spring的注解方式来直接使用
	@Value("${redis.ip}")
	private String host;
	@Value("${redis.port}")
	private int port;

	// 设置为0的话就是永远都不会过期
	private int expire = 0;

	// 定义一个管理池,所有的redisManager共同使用。
	private static JedisPool jedisPool = null;

	public RedisManager() {
	}

	/**
	 * 
	 * 初始化方法,在这个方法中通过host和port来初始化jedispool。
	 * 
	 * */

	public void init() {
		if (null == host || 0 == port) {
			System.out.println("请初始化redis配置文件");
			throw new NullPointerException("找不到redis配置");
		}
		if (jedisPool == null) {
			jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
		}
	}

	/**
	 * get value from redis
	 * 
	 * @param key
	 * @return
	 */
	public byte[] get(byte[] key) {
		byte[] value = null;
		Jedis jedis = jedisPool.getResource();
		try {
			value = jedis.get(key);
		} finally {
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	/**
	 * get value from redis
	 * 
	 * @param key
	 * @return
	 */
	public String get(String key) {
		String value = null;
		Jedis jedis = jedisPool.getResource();
		try {
			value = jedis.get(key);
		} finally {
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	/**
	 * set
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public byte[] set(byte[] key, byte[] value) {
		Jedis jedis = jedisPool.getResource();
		try {
			jedis.set(key, value);
			if (this.expire != 0) {
				jedis.expire(key, this.expire);
			}
		} finally {
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	/**
	 * set
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public String set(String key, String value) {
		Jedis jedis = jedisPool.getResource();
		try {
			jedis.set(key, value);
			if (this.expire != 0) {
				jedis.expire(key, this.expire);
			}
		} finally {
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	/**
	 * set
	 * 
	 * @param key
	 * @param value
	 * @param expire
	 * @return
	 */
	public byte[] set(byte[] key, byte[] value, int expire) {
		Jedis jedis = jedisPool.getResource();
		try {
			jedis.set(key, value);
			if (expire != 0) {
				jedis.expire(key, expire);
			}
		} finally {
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	/**
	 * set
	 * 
	 * @param key
	 * @param value
	 * @param expire
	 * @return
	 */
	public String set(String key, String value, int expire) {
		Jedis jedis = jedisPool.getResource();
		try {
			jedis.set(key, value);
			if (expire != 0) {
				jedis.expire(key, expire);
			}
		} finally {
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	/**
	 * del
	 * 
	 * @param key
	 */
	public void del(byte[] key) {
		Jedis jedis = jedisPool.getResource();
		try {
			jedis.del(key);
		} finally {
			jedisPool.returnResource(jedis);
		}
	}

	/**
	 * del
	 * 
	 * @param key
	 */
	public void del(String key) {
		Jedis jedis = jedisPool.getResource();
		try {
			jedis.del(key);
		} finally {
			jedisPool.returnResource(jedis);
		}
	}

	/**
	 * flush
	 */
	public void flushDB() {
		Jedis jedis = jedisPool.getResource();
		try {
			jedis.flushDB();
		} finally {
			jedisPool.returnResource(jedis);
		}
	}

	/**
	 * size
	 */
	public Long dbSize() {
		Long dbSize = 0L;
		Jedis jedis = jedisPool.getResource();
		try {
			dbSize = jedis.dbSize();
		} finally {
			jedisPool.returnResource(jedis);
		}
		return dbSize;
	}

	/**
	 * keys
	 * 
	 * @param regex
	 * @return
	 */
	public Set keys(String pattern) {
		Set keys = null;
		Jedis jedis = jedisPool.getResource();
		try {
			keys = jedis.keys(pattern.getBytes());
		} finally {
			jedisPool.returnResource(jedis);
		}
		return keys;
	}

	public void dels(String pattern) {
		Set keys = null;
		Jedis jedis = jedisPool.getResource();
		try {
			keys = jedis.keys(pattern.getBytes());
			Iterator ito = keys.iterator();
			while (ito.hasNext()) {
				jedis.del(ito.next());
			}
		} finally {
			jedisPool.returnResource(jedis);
		}
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public int getExpire() {
		return expire;
	}

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


这里的redisManager是通过spring来进行管理的,[email protected]properties文件的内容如下:
	redis.ip=127.0.0.1
	     redis.port=6379


ip定义为本机的ip,端口是redis默认的6379端口。
	
		
			
				classpath:/config/jdbc.properties
				classpath:/config/redis.properties
			
		
	
在spring中就是在这个地方把reids服务的配置文件redis.properties文件加载到spring中管理的。

这样redis服务就集成到了项目中,具体的使用,通过对shiro默认缓存和session数据的缓存的保存过程来展示。
项目中遇到的问题是这样的,在同时使用一个机器使用多个web容器或者多个机器同时来为一个项目进行负载均衡时,shiro的默认缓存和session数据无法在多个web容器或者多个机器之间进行同步。为了达到多web容器或多机器负载均衡的目的,我们修改了shiro的默认session管理器和缓存管理器来使shiro通过redis来管理session和缓存。这样多个web容器或机器之间的数据就可以互通共用了。 首先是shiro的配置文件,我用的是spring集成的方式。


	
	
		
	

	
	
		
		
		
		
	

	
	
		
		
		
		
		
		
	

	
	

	
	
		
		
		
	

	
		
		
		
	

	
	
		
		
		
	

	
	
		
		
	

	
	
		
		
	

	
	
		
		
		
		
		
		
	

	
		//自己定义的sessiondao
	

	
		   
	
	//注册上面实现的redisManager到spring中

	
		
	

	
		
	
	
	
		
		
		
	

	
	
		
		
	

	
	
		
		
		
		
	

	

	
	
		
		
		
		
		
			
				
				
			
		
		
			
				/img/** =anon
				/ueditor//upload/** =anon
				/login = authc
				/authenticated = authc
				/css/** = anon
				/common/** = anon
				/js/** = anon
				/admin/** = user,sysUser
				//*=anon
			
		
	

	
	



主要看上图的红色部分:其中customShiroSessionDAO、jedisShiroSessionRepository用来处理session;customShiroCacheManager、jedisShiroCacheManager用来处理缓存。
他们的源代码如下:
package org.calonlan.security.component;

import java.io.Serializable;
import java.util.Collection;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;

public class CustomShiroSessionDao extends AbstractSessionDAO {

	private ShiroSessionRepository shiroSessionRepository;

	public ShiroSessionRepository getShiroSessionRepository() {
		return shiroSessionRepository;
	}

	public void setShiroSessionRepository(
			ShiroSessionRepository shiroSessionRepository) {
		this.shiroSessionRepository = shiroSessionRepository;
	}

	@Override
	public void delete(Session session) {
		if (session == null) {
			System.out.println("错误");
			return;
		}
		Serializable id = session.getId();
		if (id != null)
			getShiroSessionRepository().deleteSession(id);

	}

	@Override
	public Collection getActiveSessions() {
		return getShiroSessionRepository().getAllSessions();
	}

	@Override
	public void update(Session session) throws UnknownSessionException {
		getShiroSessionRepository().saveSession(session);
	}

	@Override
	protected Serializable doCreate(Session session) {
		Serializable sessionId = this.generateSessionId(session);
		this.assignSessionId(session, sessionId);
		getShiroSessionRepository().saveSession(session);
		return sessionId;
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		return getShiroSessionRepository().getSession(sessionId);
	}

}


这里我们是继承了shiro的AbstractSessionDAO,然后仿照shiro的模式,给他一个shiroSessionRepository,来进行详细的session存储操作。
package org.calonlan.security.component;

import java.io.Serializable;
import java.util.Collection;

import org.apache.shiro.session.Session;

public interface ShiroSessionRepository {

	void saveSession(Session session);

	void deleteSession(Serializable sessionId);

	Session getSession(Serializable sessionId);

	Collection getAllSessions();
}

package org.calonlan.security.component;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.session.Session;

public class JedisShiroSessionRepository implements ShiroSessionRepository {

	/**
	 * 
	 * redis session key 前缀
	 * 
	 * */
	private final String REDIS_SHIRO_SESSION = "shiro-session";

	private RedisManager redisManager;

	@Override
	public void saveSession(Session session) {
		redisManager.init();
		if (session == null || session.getId() == null) {
			System.out.println("session 或者 session ID 为空");
		}
		byte[] key = SerializeUtils.serialize(getRedisSessionKey(session
				.getId()));
		byte[] value = SerializeUtils.serialize(session);

		Long timeOut = session.getTimeout() / 1000;
		redisManager.set(key, value, Integer.parseInt(timeOut.toString()));

	}

	@Override
	public void deleteSession(Serializable sessionId) {
		redisManager.init();
		if (sessionId == null) {
			System.out.println("id为空");
		}
		redisManager.del(SerializeUtils
				.serialize(getRedisSessionKey(sessionId)));

	}

	@Override
	public Session getSession(Serializable sessionId) {
		redisManager.init();
		if (null == sessionId) {
			System.out.println("id为空");
			return null;
		}
		Session session = null;
		byte[] value = redisManager.get(SerializeUtils
				.serialize(getRedisSessionKey(sessionId)));
		if (null == value)
			return null;
		session = (Session) SerializeUtils.deserialize(value);
		return session;
	}

	@Override
	public Collection getAllSessions() {
		redisManager.init();
		Set sessions = new HashSet();
		Set byteKeys = redisManager
				.keys(this.REDIS_SHIRO_SESSION + "*");
		if (byteKeys != null && byteKeys.size() > 0) {
			for (byte[] bs : byteKeys) {
				Session s = (Session) SerializeUtils.deserialize(redisManager
						.get(bs));
				sessions.add(s);
			}
		}
		return sessions;
	}

	/**
	 * 获取redis中的session key
	 * 
	 * @param sessionId
	 * @return
	 */
	private String getRedisSessionKey(Serializable sessionId) {
		return this.REDIS_SHIRO_SESSION + sessionId;
	}

	public RedisManager getRedisManager() {
		return redisManager;
	}

	public void setRedisManager(RedisManager redisManager) {
		this.redisManager = redisManager;
	}

	public JedisShiroSessionRepository() {

	}

	// public static void main(String[] args) {
	// Jedis jj = new Jedis("localhost");
	// //jj.set("key2", "232323231=========");
	// String ss = jj.get("key1");
	// System.out.println(jj.get("key2"));
	// System.out.println(ss);
	// }
}

package org.calonlan.security.component;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.util.Destroyable;

public class CustomShiroCacheManager implements CacheManager, Destroyable {

	private ShiroCacheManager shrioCacheManager;

	public ShiroCacheManager getShrioCacheManager() {
		return shrioCacheManager;
	}

	public void setShrioCacheManager(ShiroCacheManager shrioCacheManager) {
		this.shrioCacheManager = shrioCacheManager;
	}

	@Override
	public void destroy() throws Exception {
		getShrioCacheManager().destroy();
	}

	@Override
	public  Cache getCache(String name) throws CacheException {
		return getShrioCacheManager().getCache(name);
	}

}


package org.calonlan.security.component;

import org.apache.shiro.cache.Cache;

public interface ShiroCacheManager {
	 Cache getCache(String name);  
	  
    void destroy();  
}


package org.calonlan.security.component;

import org.apache.shiro.cache.Cache;

public class JedisShiroCacheManager implements ShiroCacheManager {

	private RedisManager redisManager;

	public RedisManager getRedisManager() {
		return redisManager;
	}

	public void setRedisManager(RedisManager redisManager) {
		this.redisManager = redisManager;
	}

	@Override
	public  Cache getCache(String name) {
		return new JedisShiroCache(redisManager, name);
	}

	@Override
	public void destroy() {
		redisManager.init();
		redisManager.flushDB();
	}

}


具体的使用就如如上代码所示,为什么要弄一个什么ShiroCacheManager和ShiroSessionRepository接口呢,我想各位大侠也能知道的。有了这个两个接口,我们就可以通过这个两个接口来实现更多形式的shiro的session和缓存的管理了。

在很多地方使用到了SerializeUtils,它的作用就是把对象转化为byte数组,或把byte数组转化为对象。源代码如下:
package org.calonlan.security.component;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializeUtils {

	public static byte[] serialize(Object o) {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		try {
			ObjectOutputStream outo = new ObjectOutputStream(out);
			outo.writeObject(o);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return out.toByteArray();
	}

	public static Object deserialize(byte[] b) {
		ObjectInputStream oin;
		try {
			oin = new ObjectInputStream(new ByteArrayInputStream(b));
			try {
				return oin.readObject();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}

	}
}


然后项目的运行结果如下: \
从图中可以看到,我登录后,session信息已经保存到了redis数据库中。多个tomcat做负载均衡的测试结果也很良好,但是我这个笔记本没有安装那种环境,所以无法测试。这都是个人一点小东西,各位大神勿喷。

Tags:

相关文章

    文章评论

    最 近 更 新
    热 点 排 行
    Js与CSS工具
    代码转换工具
    
    <