org.iherus.shiro.cache.redis.RedisCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shiro-redis Show documentation
Show all versions of shiro-redis Show documentation
Shiro cache Integration Adapter.
/**
* Copyright (c) 2016-2019, Bosco.Liao ([email protected]).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.iherus.shiro.cache.redis;
import static org.iherus.shiro.cache.redis.Constant.DEFAULT_CACHE_EXPIRATION;
import static org.iherus.shiro.cache.redis.serializer.StringSerializer.UTF_8;
import static org.iherus.shiro.util.Utils.assertNotBlank;
import static org.iherus.shiro.util.Utils.assertNotNull;
import static org.iherus.shiro.util.Utils.invokeMethod;
import static org.iherus.shiro.util.Utils.isEmpty;
import static org.iherus.shiro.util.Utils.mergeAll;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.iherus.shiro.cache.redis.ExpiredCache.Named;
import org.iherus.shiro.cache.redis.connection.RedisConnection;
import org.iherus.shiro.util.Md5Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 缓存接口实现类
* Description:实现Shiro缓存接口,提供集中式缓存对象的增删查改。
*
* @author Bosco.Liao
* @since 1.0.0
*/
public class RedisCache implements Cache, ExpiredCache, Named {
private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
private final String name;
private final RedisOperations operations;
private String keyPrefix;
private Duration expiration;
private Optional database;
public RedisCache(String name, RedisOperations operations) {
assertNotBlank(name, "Name must not be blank.");
assertNotNull(operations, "RedisOperations must not be null.");
this.name = name;
this.operations = operations;
this.database = Optional.empty();
}
public RedisCache(String name, RedisOperations operations, String keyPrefix, Duration expiration,
Integer database) {
this(name, operations);
this.keyPrefix = keyPrefix;
this.expiration = expiration;
this.database = Optional.ofNullable(database);
}
@Override
public String getName() {
return this.name;
}
public RedisOperations getOperations() {
return operations;
}
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public Duration getExpiration() {
return expiration;
}
public void setExpiration(Duration expiration) {
this.expiration = expiration;
}
public Optional getDatabase() {
return database;
}
public void setDatabase(Integer database) {
this.database = Optional.ofNullable(database);
}
protected void selectDatabase(RedisConnection connection) {
this.database.filter(db -> db >= 0 && !connection.isClusterConnection())
.ifPresent(it -> invokeMethod(connection, "setDatabase", Integer.class, it));
}
@SuppressWarnings("unchecked")
@Override
public V get(K key) throws CacheException {
if (logger.isDebugEnabled()) {
logger.debug("Getting object from cache [" + getName() + "] for key [" + key + "]");
}
if (key == null) {
return null;
}
try {
return (V) operations.execute((connection) -> {
selectDatabase(connection);
byte[] value = connection.get(getKeyToBytes(key));
if (logger.isDebugEnabled() && (!isEmpty(value))) {
logger.debug("Cache for [" + key + "] is exist, ready to deserialize it.");
}
return deserializeValue(value);
});
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public V put(K key, V value) throws CacheException {
return put(key, value, null);
}
@SuppressWarnings("unchecked")
@Override
public V put(K key, V value, Duration expired) throws CacheException {
if (logger.isDebugEnabled()) {
logger.debug("Putting object in cache [" + getName() + "] for key [" + key + "]");
}
if (key == null) {
return value;
}
try {
return (V) operations.execute((connection) -> {
selectDatabase(connection);
Duration expirationToUse = expired != null ? expired : (getExpiration() == null ? DEFAULT_CACHE_EXPIRATION : getExpiration());
byte[] previous = connection.set(getKeyToBytes(key), serializeValue(value), expirationToUse);
return deserializeValue(previous);
});
} catch (Exception e) {
throw new CacheException(e);
}
}
@SuppressWarnings("unchecked")
@Override
public V remove(K key) throws CacheException {
if (logger.isDebugEnabled()) {
logger.debug("Removing object from cache [" + getName() + "] for key [" + key + "]");
}
if (key == null) {
return null;
}
try {
return (V) operations.execute((connection) -> {
selectDatabase(connection);
byte[] previous = connection.del(getKeyToBytes(key));
if (logger.isDebugEnabled() && (!isEmpty(previous))) {
logger.debug("Remove key [{}] successfully.", key);
}
return deserializeValue(previous);
});
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public void clear() throws CacheException {
if (logger.isDebugEnabled()) {
logger.debug("Clear all cached objects.");
}
try {
operations.execute((connection) -> {
selectDatabase(connection);
Set allKeys = connection.keys(UTF_8.serialize(getKeyPrefix() + "*"));
if (logger.isDebugEnabled() && (!allKeys.isEmpty())) {
logger.debug("Currently scanning to {} keys, ready to clear.", allKeys.size());
}
Long c = connection.mdel(allKeys.toArray(new byte[allKeys.size()][]));
if (logger.isDebugEnabled() && c != null) {
logger.debug("After the cleanup is completed, this task clears {} cache objects.", c);
}
return c;
});
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public int size() {
try {
return operations.execute((connection) -> {
selectDatabase(connection);
return connection.size(UTF_8.serialize(getKeyPrefix() + "*"));
}).intValue();
} catch (Exception e) {
throw new CacheException(e);
}
}
/**
* Because the final type of the cache instance is {@literal cache
© 2015 - 2025 Weber Informatics LLC | Privacy Policy