参考资料:http://blog.csdn.net/lishehe/article/details/45223823
大神写的非常棒,只是缺少了几个工具类,我在这里给出了自己的代码,方便用到。
1. redis.properties
redis.host=127.0.0.1
redis.port=6379
redis.default.db=2
redis.timeout=100000
redis.maxIdle=100
redis.maxWaitMillis=30000
redis.testOnBorrow=true
2. applicationContext-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--配置 session 管理-->
<property name="sessionManager" ref="sessionManager"/>
<!--配置 记住我-->
<property name="rememberMeManager" ref="rememberMeManager"/>
<!-- 配置多个Realm的登录认证 -->
<property name="authenticator" ref="authenticator"/>
<!-- 配置多个Realm的权限认证 -->
<property name="authorizer" ref="authorizer"/>
<!-- redis缓存 -->
<property name="cacheManager" ref="redisCacheManager" />
</bean>
<!--配置多个 realm 的权限权限认证-->
<bean id="authorizer" class="org.apache.shiro.authz.ModularRealmAuthorizer">
<property name="realms">
<list>
<!--这个实现权限匹配的方法-->
<ref bean="myRealm"/>
</list>
</property>
</bean>
<!-- 配置多个Realm -->
<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
<!--验证的时候,是用迭代器,所以可以认为验证的顺序就是这个 list 的顺序-->
<property name="realms">
<list>
<!--<ref bean="otherRealm"/>-->
<ref bean="myRealm"/>
</list>
</property>
<property name="authenticationStrategy">
<!--所有 realm 认证通过才算登录成功-->
<!--<bean id="authenticationStrategy" class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"/>-->
<!--验证某个 realm 成功后直接返回,不会验证后面的 realm 了-->
<bean id="authenticationStrategy" class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"/>
<!--所有的 realm 都会验证,其中一个成功,也会继续验证后面的 realm,最后返回成功-->
<!--<bean id="authenticationStrategy" class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"/>-->
</property>
</bean>
<!--自定义 MyRealm,登录的认证入口 ,需要继承AuthorizingRealm,项目中会体现-->
<bean id="myRealm" class="com.tms.shiro.MyRealm">
<!-- 配置密码匹配器 -->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 加密算法为SHA-256 -->
<property name="hashAlgorithmName" value="SHA-256"/>
<!-- 加密迭代次数 -->
<property name="hashIterations" value="1024"/>
<!--是否存储散列后的密码为16进制,为 true:.toHex(),为 false:.toBase64()-->
<property name="storedCredentialsHexEncoded" value="false"/>
</bean>
</property>
</bean>
<!--rememberMeManager管理 配置-->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie">
<bean class="org.apache.shiro.web.servlet.SimpleCookie">
<!--设置超时时间 单位 秒,一天=86400-->
<constructor-arg value="shiro-cookie"/>
<property name="maxAge" value="86400"/>
<property name="httpOnly" value="true"/>
</bean>
</property>
</bean>
<!--session管理 配置-->
<!--<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">-->
<!--<bean id="sessionManager" class="com.tms.shiro.SessionManager">
<!–session 过期时间 单位 毫秒,2400000=40min–>
<property name="globalSessionTimeout" value="2400000"/>
<!–有需要可以自行配置–>
<!–<property name="cacheManager" ref="xxxx"></property>–>
<!–有需要可以自行配置–>
<!–<property name="sessionDAO" ref="xxx"></property>–>
<property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>-->
<!-- 自定义sessionId 防止同tomcat 等容器冲突 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="token"/>
<property name="maxAge" value="86400"/>
<property name="path" value="/"/>
</bean>
<!--shiro 请求拦截器,这里的 bean id 一定要对应 web.xml 中的filter-name,否则找不到这个拦截器-->
<bean id="shiroFilter" class="com.tms.shiro.MyShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!--登录地址-->
<property name="loginUrl" value="login"/>
<!--登录成功跳转的地址-->
<property name="successUrl" value="/userAction_findList"/>
<!--权限认证失败跳转的地址-->
<property name="unauthorizedUrl" value="error"/>
<!--需要权限拦截的路径-->
<property name="filterChainDefinitions">
<value>
<!--/login = anon-->
<!--/validateCode = anon-->
<!--/** = authc-->
</value>
</property>
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 ,不明觉厉,没有深究-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- 自定义redisManager-redis -->
<bean id="redisCacheManager" class="com.tms.util.redis.RedisCacheManager">
<property name="redisManager" ref="redisManager" />
</bean>
<!-- 自定义cacheManager -->
<bean id="redisCache" class="com.tms.util.redis.RedisCache">
<constructor-arg ref="redisManager"></constructor-arg>
</bean>
<bean id="redisManager" class="com.tms.util.redis.RedisManager"></bean>
<!-- session会话存储的实现类 -->
<bean id="redisShiroSessionDAO" class="com.tms.util.redis.RedisSessionDao">
<property name="redisManager" ref="redisManager" />
</bean>
<!-- session管理器 -->
<bean id="sessionManager"
class="com.tms.shiro.SessionManager">
<!-- 设置全局会话超时时间,默认30分钟(1800000) -->
<property name="globalSessionTimeout" value="1800000" />
<!-- 是否在会话过期后会调用SessionDAO的delete方法删除会话 默认true -->
<property name="deleteInvalidSessions" value="true" />
<!-- 会话验证器调度时间 -->
<property name="sessionValidationInterval" value="1800000" />
<!-- session存储的实现 -->
<property name="sessionDAO" ref="redisShiroSessionDAO" />
<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
<property name="sessionIdCookie" ref="sharesession" />
<!-- 定时检查失效的session -->
<property name="sessionValidationSchedulerEnabled" value="true" />
</bean>
<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
<bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- cookie的name,对应的默认是 JSESSIONID -->
<constructor-arg name="name" value="SHAREJSESSIONID" />
<!-- jsessionId的path为 / 用于多个系统共享jsessionId -->
<property name="path" value="/" />
<property name="httpOnly" value="true"/>
</bean>
<!-- shiro的自带缓存管理器encahe -->
<!-- <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> -->
<!-- <property name="cacheManagerConfigFile" value="classpath:config/ehcache-shiro.xml"
/> -->
<!-- </bean> -->
<!-- 开启shiro的注解,需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 -->
<bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"></bean>
<bean
class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
</beans>
3. redis.xml
<?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:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 加载Reids属性配置文件 ignore-unresolvable="true"-->
<context:property-placeholder
location="classpath:redis.properties"/>
<bean id="propertyConfigurerRedis"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="order" value="1"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="systemPropertiesMode" value="1"/>
<property name="searchSystemEnvironment" value="true"/>
<property name="locations">
<list>
<value>classpath:redis.properties</value>
</list>
</property>
</bean>
<!--支持缓存注释, 使用key生成器-->
<bean id="redisCacheKeyGenerator" class="com.tms.util.redis.CustomRedisCacheKeyGenerator"/>
<cache:annotation-driven key-generator="redisCacheKeyGenerator"/>
<!-- 配置redis池,最大空闲实例数,(创建实例时)最大等待时间,(创建实例时)是否验证 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
<property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="timeBetweenEvictionRunsMillis" value="6000"/>
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="usePool" value="true"></property>
<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="timeout" value="${redis.timeout}"/>
<property name="database" value="${redis.default.db}"></property>
<property name="poolConfig" ref="jedisPoolConfig"></property>
</bean>
<bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean>
<!--V2 配置cacheManager, 使用默认的 用户自定义的 RedisCacheManager -->
<bean id="cacheManager" class="com.tms.util.redis.CustomizedRedisCacheManager">
<constructor-arg ref="jedisTemplate"/>
<!--使用前缀,使用以后,以cache的value作为redis中的namespace,缓存的键也会加入这个前缀-->
<property name="usePrefix" value="true"/>
<!-- 前缀命名,仅当usePrefix为true时才生效,本例子不使用 -->
<!--<property name="cachePrefix">-->
<!--<bean class="org.springframework.data.redis.cache.DefaultRedisCachePrefix">-->
<!--<constructor-arg name="delimiter" value=":"/>-->
<!--</bean>-->
<!--</property>-->
<!-- 默认有效期1h ,本例子不使用-->
<!--<property name="defaultExpiration" value="3600"/>-->
</bean>
</beans>
4. SerializerUtil.java
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
/**
* @Author:
* @Date: 2018-03-13 12:33
* @Modified By:
* @Description:
*/
public class SerializerUtil {
private static final JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
/**
* 序列化对象
* @param obj
* @return
*/
public static <T> byte[] serialize(T obj){
try {
return jdkSerializationRedisSerializer.serialize(obj);
} catch (Exception e) {
throw new RuntimeException("序列化失败!", e);
}
}
/**
* 反序列化对象
* @param bytes 字节数组
* @param
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T deserialize(byte[] bytes){
try {
return (T) jdkSerializationRedisSerializer.deserialize(bytes);
} catch (Exception e) {
throw new RuntimeException("反序列化失败!", e);
}
}
}
5. RedisSessionDao.java
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* @Author:
* @Date: 2018-03-13 12:35
* @Modified By:
* @Description:
*/
public class RedisSessionDao extends AbstractSessionDAO {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private RedisManager redisManager;
/**
* The Redis key prefix for the sessions
*/
private static final String KEY_PREFIX = "shiro_redis_session:";
private byte[] getByteKey(String key){
return key.getBytes();
}
@Override
public void update(Session session) throws UnknownSessionException {
this.saveSession(session);
}
@Override
public void delete(Session session) {
if (session == null || session.getId() == null) {
logger.error("session or session id is null");
return;
}
redisManager.del(getByteKey(KEY_PREFIX + session.getId()));
}
@Override
public Collection<Session> getActiveSessions() {
Set<Session> sessions = new HashSet<Session>();
Set<byte[]> keys = redisManager.keys(KEY_PREFIX + "*");
if(keys != null && keys.size()>0){
for(byte[] key : keys){
Session s = (Session) SerializerUtil.deserialize(redisManager.get(SerializerUtil.deserialize(key)));
sessions.add(s);
}
}
return sessions;
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
this.saveSession(session);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
if(sessionId == null){
logger.error("session id is null");
return null;
}
Session s = (Session)redisManager.get(getByteKey(KEY_PREFIX + sessionId));
return s;
}
private void saveSession(Session session) throws UnknownSessionException{
if (session == null || session.getId() == null) {
logger.error("session or session id is null");
return;
}
//设置过期时间
long expireTime = 1800000l;
session.setTimeout(expireTime);
redisManager.setEx(KEY_PREFIX + session.getId(), session, expireTime);
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
}
public RedisManager getRedisManager() {
return redisManager;
}
}
6. RedisManager.java
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.dao.DataAccessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import java.io.Serializable;
import java.util.Set;
/**
* @Author:
* @Date: 2018-03-13 12:30
* @Modified By:
* @Description:
*/
public class RedisManager {
@Autowired
private RedisTemplate<Serializable, Serializable> redisTemplate;
/**
* 过期时间
*/
/**
* 添加缓存数据(给定key已存在,进行覆盖)
* @param key
* @param obj
* @throws DataAccessException
*/
public <T> void set(byte[] key, T obj) throws DataAccessException{
final byte[] bkey = key;
final byte[] bvalue = SerializerUtil.serialize(obj);
redisTemplate.execute(new RedisCallback<Void>() {
@Override
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.set(bkey, bvalue);
return null;
}
});
}
/**
* 添加缓存数据(给定key已存在,不进行覆盖,直接返回false)
* @param key
* @param obj
* @return 操作成功返回true,否则返回false
* @throws DataAccessException
*/
public <T> boolean setNX(String key, T obj) throws DataAccessException{
final byte[] bkey = key.getBytes();
final byte[] bvalue = SerializerUtil.serialize(obj);
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.setNX(bkey, bvalue);
}
});
return result;
}
/**
* 添加缓存数据,设定缓存失效时间
* @param key
* @param obj
* @param expireSeconds 过期时间,单位 秒
* @throws DataAccessException
*/
public <T> void setEx(String key, T obj, final long expireSeconds) throws DataAccessException{
final byte[] bkey = key.getBytes();
final byte[] bvalue = SerializerUtil.serialize(obj);
redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
connection.setEx(bkey, expireSeconds, bvalue);
return true;
}
});
}
/**
* 获取key对应value
* @param key
* @return
* @throws DataAccessException
*/
public <T> T get(final byte[] key) throws DataAccessException{
byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
@Override
public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
return connection.get(key);
}
});
if (result == null) {
return null;
}
return SerializerUtil.deserialize(result);
}
/**
* 删除指定key数据
* @param key
* @return 返回操作影响记录数
*/
public Long del(final byte[] key){
if (key.length == 0) {
return 0l;
}
Long delNum = redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
byte[] keys = key;
return connection.del(keys);
}
});
return delNum;
}
public Set<byte[]> keys(final String key){
if (StringUtils.isEmpty(key)) {
return null;
}
Set<byte[]> bytesSet = redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
@Override
public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
byte[] keys = key.getBytes();
return connection.keys(keys);
}
});
return bytesSet;
}
/**
* dbSize
*/
public Long dbSize(){
Long delNum = redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.dbSize();
}
});
return delNum;
}
/**
* flushDB
*/
public void flushDB() throws DataAccessException{
redisTemplate.execute(new RedisCallback<Void>() {
@Override
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.flushDb();
return null;
}
});
}}
7. RedisCacheManager.java
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @Author:
* @Date: 2018-03-13 14:08
* @Modified By:
* @Description:
*/
public class RedisCacheManager implements CacheManager{
private static final Logger logger = LoggerFactory
.getLogger(RedisCacheManager.class);
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
private RedisManager redisManager;
/**
* The Redis key prefix for caches
*/
private String keyPrefix = "shiro_redis_cache:";
/**
* Returns the Redis session keys
* prefix.
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
}
/**
* Sets the Redis sessions key
* prefix.
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
logger.debug("获取名称为: " + name + " 的RedisCache实例");
Cache c = caches.get(name);
if (c == null) {
// initialize the Redis manager instance
redisManager.init();
// create a new cache instance
c = new RedisCache<K, V>(redisManager, keyPrefix);
// add it to the cache collection
caches.put(name, c);
}
return c;
}
public RedisManager getRedisManager() {
return redisManager;
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
}
}
8. RedisCache.java
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* @Author:
* @Date: 2018-03-13 14:10
* @Modified By:
* @Description:
*/
public class RedisCache<K,V> implements Cache<K,V> {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* The wrapped Jedis instance.
*/
private RedisManager cache;
/**
* The Redis key prefix for the sessions
*/
private String keyPrefix = "shiro_redis_session:";
/**
* Returns the Redis session keys
* prefix.
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
}
/**
* Sets the Redis sessions key
* prefix.
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
/**
* 通过一个JedisManager实例构造RedisCache
*/
public RedisCache(RedisManager cache){
if (cache == null) {
throw new IllegalArgumentException("Cache argument cannot be null.");
}
this.cache = cache;
}
/**
* Constructs a cache instance with the specified
* Redis manager and using a custom key prefix.
* @param cache The cache manager instance
* @param prefix The Redis key prefix
*/
public RedisCache(RedisManager cache,
String prefix){
this( cache );
this.keyPrefix = prefix;
}
/**
* 获得byte[]型的key
* @param key
* @return
*/
private byte[] getByteKey(K key){
if(key instanceof String){
String preKey = this.keyPrefix + key;
return preKey.getBytes();
}else{
return SerializerUtil.serialize(key);
}
}
@Override
public V get(K key) throws CacheException {
logger.debug("根据key从Redis中获取对象 key [" + key + "]");
try {
if (key == null) {
return null;
}else{
byte[] rawValue = cache.get(getByteKey(key));
@SuppressWarnings("unchecked")
V value = (V) SerializerUtil.deserialize(rawValue);
return value;
}
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public V put(K key, V value) throws CacheException {
logger.debug("根据key从存储 key [" + key + "]");
try {
cache.set(getByteKey(key), SerializerUtil.serialize(value));
return value;
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public V remove(K key) throws CacheException {
logger.debug("从redis中删除 key [" + key + "]");
try {
V previous = get(key);
cache.del(getByteKey(key));
return previous;
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public void clear() throws CacheException {
logger.debug("从redis中删除所有元素");
try {
cache.flushDB();
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public int size() {
try {
Long longSize = new Long(cache.dbSize());
return longSize.intValue();
} catch (Throwable t) {
throw new CacheException(t);
}
}
@SuppressWarnings("unchecked")
@Override
public Set<K> keys() {
try {
Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
if (CollectionUtils.isEmpty(keys)) {
return Collections.emptySet();
}else{
Set<K> newKeys = new HashSet<K>();
for(byte[] key:keys){
newKeys.add((K)key);
}
return newKeys;
}
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public Collection<V> values() {
try {
Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
if (!CollectionUtils.isEmpty(keys)) {
List<V> values = new ArrayList<V>(keys.size());
for (byte[] key : keys) {
@SuppressWarnings("unchecked")
V value = get((K)key);
if (value != null) {
values.add(value);
}
}
return Collections.unmodifiableList(values);
} else {
return Collections.emptyList();
}
} catch (Throwable t) {
throw new CacheException(t);
}
}
}