Commit 880890a7 by s_guodong

缓存优化,可配置

parent 7371e304
......@@ -53,7 +53,7 @@ public class AuthInterceptor implements HandlerInterceptor {
private String getTokenKey(HttpServletRequest request){
String logName = request.getHeader("token");
if(logName == null || "undefined".equals(logName))
logName = "ZL";
logName = "sun123";
//现在仅仅以userId这个来实现
return logName;
}
......@@ -105,7 +105,7 @@ public class AuthInterceptor implements HandlerInterceptor {
String logName = request.getHeader("userId");
if(logName == null || "undefined".equals(logName))
logName = "ZL";
logName = "sun123";
String token = getTokenKey(request);
//目前采用自动登录模式认证
getOrCreateAuthInfo(token,logName);
......
......@@ -5,38 +5,39 @@ server:
spring:
datasource:
driver-class-name: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@114.115.138.98:9400:XE
username: TEST
password: test
type: com.alibaba.druid.pool.DruidDataSource
# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
# druid 配置: https://github.com/alibaba/druid/wiki/
#初始化链接数
initialSize: 1
minIdle: 1
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: select 1 from dual
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,stat用于监控界面,'wall'用于防火墙防御sql注入, slf4j用于druid记录sql日志
filters: stat,slf4j
#,wall
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
useGlobalDataSourceStat: false
druid:
driver-class-name: oracle.jdbc.driver.OracleDriver
url: jdbc:oracle:thin:@114.115.138.98:9400:XE
username: TEST
password: test
type: com.alibaba.druid.pool.DruidDataSource
# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
# druid 配置: https://github.com/alibaba/druid/wiki/
#初始化链接数
initialSize: 1
minIdle: 1
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: select 1 from dual
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,stat用于监控界面,'wall'用于防火墙防御sql注入, slf4j用于druid记录sql日志
filters: stat,slf4j
#,wall
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
useGlobalDataSourceStat: false
redis:
host: 127.0.0.1
database: 0
......@@ -45,4 +46,11 @@ spring:
envConfig:
rootPath: workRoot
\ No newline at end of file
rootPath: workRoot
cache:
#缓存类型(guava/redis)
type: redis
#缓存失效时间(秒)
expireAfterAccess: 3600
#序列化方式
serializer: kryo
\ No newline at end of file
......@@ -71,10 +71,6 @@
<artifactId>dom4j</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc6</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
......@@ -87,6 +83,14 @@
<artifactId>kryo5</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>12.1.0.2</version>
<scope>system</scope>
<systemPath>${basedir}/../lib/ojdbc6-12.1.0.2.jar</systemPath>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -2,6 +2,14 @@ package com.brilliance.mda.support.cache;
import com.brilliance.mda.runtime.mda.IAuthInfo;
import com.brilliance.mda.runtime.mda.IContext;
import com.brilliance.mda.support.cache.impl.GuavaCache;
import com.brilliance.mda.support.cache.impl.RedisCache;
import com.brilliance.mda.support.cache.serializer.ICacheSerializer;
import com.brilliance.mda.support.cache.serializer.ICacheSerializerEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
......@@ -13,22 +21,53 @@ import javax.annotation.Resource;
@Configuration
public class CacheConfiguration {
private static final Logger logger = LoggerFactory.getLogger(CacheConfiguration.class);
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Value("${envconfig.cache.serializer:kryo}")
private String cacheSerializerType;
@Value("${envconfig.cache.expireAfterAccess:300}")
private long expireAfterAccess;
@Bean("ctxCache")
public ICache<String, IContext> getCtxCache() {
@ConditionalOnProperty(prefix = "envconfig.cache", name = "type", havingValue = "guava", matchIfMissing = true)
public ICache<String, IContext> getGuavaCtxCache() {
//2h timeout
// return new CommonGuavaCache<>("CtxCache",2*60*60);
logger.info("使用Guava作为Context缓存");
return new GuavaCache<>("CtxCache", expireAfterAccess);
}
this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
@Bean("ctxCache")
@ConditionalOnProperty(prefix = "envconfig.cache", name = "type", havingValue = "redis")
public ICache<String, IContext> getRedisCtxCache() {
//2h timeout
ICacheSerializer cacheSerializer = getCacheSerializer();
logger.info("使用Redis作为Context缓存,序列化处理器:{}", cacheSerializer.getName());
this.redisTemplate.setKeySerializer(new StringRedisSerializer());
return new CommonRedisCache<IContext>("CtxCache", redisTemplate, 2 * 60 * 60);
this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
return new RedisCache<>("CtxCache", redisTemplate, cacheSerializer, expireAfterAccess);
}
@Bean("ctxCacheSerializer")
public ICacheSerializer getCacheSerializer() {
return ICacheSerializerEnum.getSerializer(cacheSerializerType);
}
@Bean("authCache")
public ICache<String, IAuthInfo> getAuthCache() {
//2h timeout
return new CommonGuavaCache<>("AuthCache", 2 * 60 * 60);
@ConditionalOnProperty(prefix = "envconfig.cache", name = "type", havingValue = "guava", matchIfMissing = true)
public ICache<String, IAuthInfo> getGuavaAuthCache() {
return new GuavaCache<>("AuthCache", expireAfterAccess);
}
@Bean("authCache")
@ConditionalOnProperty(prefix = "envconfig.cache", name = "type", havingValue = "redis")
public ICache<String, IAuthInfo> getRedisAuthCache() {
ICacheSerializer cacheSerializer = getCacheSerializer();
logger.info("使用Redis作为Auth缓存,序列化处理器:{}", cacheSerializer.getName());
this.redisTemplate.setKeySerializer(new StringRedisSerializer());
this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
return new RedisCache<>("AuthCache", redisTemplate, cacheSerializer, expireAfterAccess);
}
}
package com.brilliance.mda.support.cache;
import com.brilliance.mda.runtime.mda.IBaseObject;
import com.brilliance.mda.runtime.mda.IContext;
import com.brilliance.mda.runtime.mda.IModule;
import com.brilliance.mda.runtime.mda.IRuleEmitter;
import com.brilliance.mda.runtime.mda.driver.MdaEnv;
import com.brilliance.mda.runtime.mda.impl.AbstractModule;
import com.brilliance.mda.runtime.mda.impl.ModuleList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import java.lang.reflect.*;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class CommonRedisCache<V> implements ICache<String, V> {
private final Logger logger = LoggerFactory.getLogger(getClass());
private RedisTemplate<String, Object> redisTemplate;
private String cacheName;
private long expireTime;
public CommonRedisCache(String cacheName, RedisTemplate<String, Object> redisTemplate, long expireTime) {
this.cacheName = cacheName;
this.redisTemplate = redisTemplate;
this.expireTime = expireTime;
}
@Override
public String store(V v) {
String key = generateKey();
this.store(key, v);
return key;
}
@Override
public void store(String key, V v) {
try {
// Kryo
long time1 = System.currentTimeMillis();
byte[] bytes = KryoUtil.writeToByteArray(v);
logger.debug("Kryo 序列化用时:{}", System.currentTimeMillis() - time1);
logger.debug("Kryo size: {}", bytes.length);
long time2 = System.currentTimeMillis();
this.redisTemplate.opsForValue().set(key, bytes, this.expireTime, TimeUnit.SECONDS);
logger.debug("Kryo 存入redis用时:{}", System.currentTimeMillis() - time2);
// testKryoDeSerialize(key);
} catch (Exception e) {
e.printStackTrace();
logger.error("Kryo 实例序列化失败");
}
}
@Override
public V get(String s) {
try {
long time1 = System.currentTimeMillis();
byte[] bytes = (byte[]) this.redisTemplate.opsForValue().get(s);
if (bytes == null) return null;
logger.debug("Kryo 反序列化后的 size: {}", bytes.length);
logger.debug("Kryo 读取redis用时:{}", System.currentTimeMillis() - time1);
long time2 = System.currentTimeMillis();
V v = (V) KryoUtil.readFromByteArray(bytes);
IContext context = (IContext) v;
IModule root = context.getRoot();
context.setEmitter(MdaEnv.getBean(IRuleEmitter.EMITTER_PRE + root.getClass().getSimpleName().toLowerCase(), IRuleEmitter.class));
moduleSetting(root);
logger.debug("Kryo 反序列化用时:{}", System.currentTimeMillis() - time2);
return v;
} catch (Exception e) {
e.printStackTrace();
logger.error("Kryo 反序列化失败");
}
return null;
}
@Override
public void remove(String s) {
this.redisTemplate.delete(s);
}
@Override
public String generateKey() {
return this.cacheName + "-" + UUID.randomUUID();
}
public void moduleSetting(IModule module) {
invokeSetArgumentMethod(module);
Field[] fields = module.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
Class<?> clazz = field.getType();
try {
Object o = field.get(module);
if (o == null) continue;
if (AbstractModule.class.isAssignableFrom(clazz)) {
moduleSetting((IModule) o);
} else if (ModuleList.class.isAssignableFrom(clazz)) {
fillModuleList(module, field, (ModuleList<?>) o);
}
} catch (IllegalAccessException ignored) {
}
}
}
public void invokeSetArgumentMethod(IModule module) {
try {
Method setArgumentMethod = module.getClass().getMethod("setArgument");
setArgumentMethod.invoke(module);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ignored) {
}
}
public void fillModuleList(IModule parentModule, Field field, ModuleList<?> moduleList) {
try {
Class<? extends ModuleList> moduleListClass = moduleList.getClass();
Field parentField = moduleListClass.getDeclaredField("_parent");
Field nameField = moduleListClass.getDeclaredField("_name");
Field pathField = moduleListClass.getDeclaredField("_path");
Field dataClassField = moduleListClass.getDeclaredField("dataClass");
Field moduleTypeField = moduleListClass.getDeclaredField("moduleType");
parentField.setAccessible(true);
nameField.setAccessible(true);
pathField.setAccessible(true);
dataClassField.setAccessible(true);
moduleTypeField.setAccessible(true);
parentField.set(moduleList, parentModule);
nameField.set(moduleList, field.getName());
String prefix = parentModule.getPath();
if (prefix == null || prefix.length() == 0 || prefix.equals(IBaseObject.separator)) {
pathField.set(moduleList, IBaseObject.separator + field.getName());
} else {
pathField.set(moduleList, prefix + IBaseObject.separator + field.getName());
}
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType) type;
Type[] actualTypeArguments = t.getActualTypeArguments();
if (actualTypeArguments.length > 0) {
Class aClass = (Class) actualTypeArguments[0];
dataClassField.set(moduleList, aClass);
moduleTypeField.set(moduleList, aClass.getSimpleName().toLowerCase());
}
}
for (IModule module : moduleList) {
moduleSetting(module);
}
} catch (NoSuchFieldException | IllegalAccessException ignored) {
}
}
}
......@@ -9,6 +9,18 @@ public interface ICache<K, V> {
void remove(K k);
String generateKey();
default void keeplive(K key){
get(key);
}
default void cleanup(){
};
default boolean contains(K key){
return false;
};
String CTX_CACHE="ctxCache";
String AUTH_CACHE="authCache";
......
package com.brilliance.mda.support.cache;
import com.esotericsoftware.kryo.kryo5.Kryo;
import com.esotericsoftware.kryo.kryo5.io.Input;
import com.esotericsoftware.kryo.kryo5.io.Output;
import com.esotericsoftware.kryo.kryo5.objenesis.strategy.StdInstantiatorStrategy;
import com.esotericsoftware.kryo.kryo5.util.DefaultInstantiatorStrategy;
import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
public class KryoUtil {
private static final String DEFAULT_ENCODING = "UTF-8";
//每个线程的 Kryo 实例
private static final ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
Kryo kryo = new Kryo();
//kryo.setInstantiatorStrategy(new SerializingInstantiatorStrategy());
kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
/**
* 不要轻易改变这里的配置!更改之后,序列化的格式就会发生变化,
* 上线的同时就必须清除 Redis 里的所有缓存,
* 否则那些缓存再回来反序列化的时候,就会报错
*/
//支持对象循环引用(否则会栈溢出)
kryo.setReferences(true); //默认值就是 true,添加此行的目的是为了提醒维护者,不要改变这个配置
// kryo.register(SerializedLambda.class);
// kryo.register(ClosureSerializer.Closure.class, new ClosureSerializer());
// kryo.addDefaultSerializer(ModuleHolder.class,new JavaSerializer());
// kryo.addDefaultSerializer(FieldHolder.class,new JavaSerializer());
// kryo.addDefaultSerializer(FieldConstantHolder.class,new JavaSerializer());
// FieldSerializer.FieldSerializerConfig fieldSerializerConfig = new FieldSerializer.FieldSerializerConfig();
// fieldSerializerConfig.setIgnoreSyntheticFields(true);
// FieldSerializer fieldSerializer = new FieldSerializer(kryo,ModuleHolder.class,fieldSerializerConfig);
// kryo.addDefaultSerializer(ModuleHolder.class,fieldSerializer);
//
// FieldSerializer.FieldSerializerConfig fieldSerializerConfig1 = new FieldSerializer.FieldSerializerConfig();
// fieldSerializerConfig1.setIgnoreSyntheticFields(true);
// FieldSerializer fieldSerializer1 = new FieldSerializer(kryo,FieldHolder.class,fieldSerializerConfig1);
// kryo.addDefaultSerializer(FieldHolder.class,fieldSerializer1);
//
// FieldSerializer.FieldSerializerConfig fieldSerializerConfig2 = new FieldSerializer.FieldSerializerConfig();
// fieldSerializerConfig2.setIgnoreSyntheticFields(true);
// FieldSerializer fieldSerializer2 = new FieldSerializer(kryo,FieldConstantHolder.class,fieldSerializerConfig2);
// kryo.addDefaultSerializer(FieldConstantHolder.class,fieldSerializer2);
// kryo.register(Object[].class);
// kryo.register(Class.class);
// kryo.register(SerializedLambda.class);
// kryo.register(ClosureSerializer.Closure.class, new ClosureSerializer());
// kryo.register(CapturingClass.class);
//kryo.getD
//不强制要求注册类(注册行为无法保证多个 JVM 内同一个类的注册编号相同;而且业务系统中大量的 Class 也难以一一注册)
kryo.setRegistrationRequired(false); //默认值就是 false,添加此行的目的是为了提醒维护者,不要改变这个配置
//Fix the NPE bug when deserializing Collections.
// ((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy())
// .setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
return kryo;
}
};
/**
* 获得当前线程的 Kryo 实例
*
* @return 当前线程的 Kryo 实例
*/
public static Kryo getInstance() {
return kryoLocal.get();
}
//-----------------------------------------------
// 序列化/反序列化对象,及类型信息
// 序列化的结果里,包含类型的信息
// 反序列化时不再需要提供类型
//-----------------------------------------------
/**
* 将对象【及类型】序列化为字节数组
*
* @param obj 任意对象
* @param <T> 对象的类型
* @return 序列化后的字节数组
*/
public static <T> byte[] writeToByteArray(T obj) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Output output = new Output(byteArrayOutputStream);
Kryo kryo = getInstance();
kryo.writeClassAndObject(output, obj);
output.flush();
return byteArrayOutputStream.toByteArray();
}
/**
* 将对象【及类型】序列化为 String
* 利用了 Base64 编码
*
* @param obj 任意对象
* @param <T> 对象的类型
* @return 序列化后的字符串
*/
public static <T> String writeToString(T obj) {
try {
return new String(Base64.encodeBase64(writeToByteArray(obj)), DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
/**
* 将字节数组反序列化为原对象
*
* @param byteArray writeToByteArray 方法序列化后的字节数组
* @param <T> 原对象的类型
* @return 原对象
*/
@SuppressWarnings("unchecked")
public static <T> T readFromByteArray(byte[] byteArray) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
Input input = new Input(byteArrayInputStream);
Kryo kryo = getInstance();
return (T) kryo.readClassAndObject(input);
}
/**
* 将 String 反序列化为原对象
* 利用了 Base64 编码
*
* @param str writeToString 方法序列化后的字符串
* @param <T> 原对象的类型
* @return 原对象
*/
public static <T> T readFromString(String str) {
try {
return readFromByteArray(Base64.decodeBase64(str.getBytes(DEFAULT_ENCODING)));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
//-----------------------------------------------
// 只序列化/反序列化对象
// 序列化的结果里,不包含类型的信息
//-----------------------------------------------
/**
* 将对象序列化为字节数组
*
* @param obj 任意对象
* @param <T> 对象的类型
* @return 序列化后的字节数组
*/
public static <T> byte[] writeObjectToByteArray(T obj) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Output output = new Output(byteArrayOutputStream);
Kryo kryo = getInstance();
kryo.writeObject(output, obj);
output.flush();
return byteArrayOutputStream.toByteArray();
}
/**
* 将对象序列化为 String
* 利用了 Base64 编码
*
* @param obj 任意对象
* @param <T> 对象的类型
* @return 序列化后的字符串
*/
public static <T> String writeObjectToString(T obj) {
try {
return new String(Base64.encodeBase64(writeObjectToByteArray(obj)), DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
/**
* 将字节数组反序列化为原对象
*
* @param byteArray writeToByteArray 方法序列化后的字节数组
* @param clazz 原对象的 Class
* @param <T> 原对象的类型
* @return 原对象
*/
@SuppressWarnings("unchecked")
public static <T> T readObjectFromByteArray(byte[] byteArray, Class<T> clazz) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
Input input = new Input(byteArrayInputStream);
Kryo kryo = getInstance();
return kryo.readObject(input, clazz);
}
/**
* 将 String 反序列化为原对象
* 利用了 Base64 编码
*
* @param str writeToString 方法序列化后的字符串
* @param clazz 原对象的 Class
* @param <T> 原对象的类型
* @return 原对象
*/
public static <T> T readObjectFromString(String str, Class<T> clazz) {
try {
return readObjectFromByteArray(Base64.decodeBase64(str.getBytes(DEFAULT_ENCODING)), clazz);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
}
\ No newline at end of file
package com.brilliance.mda.support.cache;
package com.brilliance.mda.support.cache.impl;
import com.brilliance.mda.support.cache.ICache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
......@@ -9,14 +10,14 @@ import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.UUID;
public class CommonGuavaCache<V> implements ICache<String,V>{
public class GuavaCache<V> implements ICache<String, V> {
private final Logger logger = LoggerFactory.getLogger(CommonGuavaCache.class);
private final Logger logger = LoggerFactory.getLogger(GuavaCache.class);
private final LoadingCache<String, V> cache;
private String cacheName;
public CommonGuavaCache(String cacheName,long seconds){
public GuavaCache(String cacheName, long seconds) {
this.cacheName = cacheName;
cache = CacheBuilder.newBuilder()
.expireAfterAccess(Duration.ofSeconds(seconds))
......@@ -36,7 +37,7 @@ public class CommonGuavaCache<V> implements ICache<String,V>{
}
@Override
public void store(String key,V v){
public void store(String key, V v) {
cache.put(key, v);
}
......@@ -45,7 +46,7 @@ public class CommonGuavaCache<V> implements ICache<String,V>{
try {
return cache.get(k);
} catch (Exception e) {
logger.warn("Acquire {} cache failed",cacheName);
logger.warn("Acquire {} cache failed", cacheName);
}
return null;
}
......@@ -60,4 +61,15 @@ public class CommonGuavaCache<V> implements ICache<String,V>{
return UUID.randomUUID().toString();
}
@Override
public void cleanup() {
logger.info("{} clean up start.size:{}",this.cacheName,cache.size());
this.cache.cleanUp();
logger.info("{} clean up over.size:{}",this.cacheName,cache.size());
}
@Override
public boolean contains(String key) {
return this.get(key) != null;
}
}
package com.brilliance.mda.support.cache.impl;
import com.brilliance.mda.runtime.mda.RuleExecuteException;
import com.brilliance.mda.support.cache.ICache;
import com.brilliance.mda.support.cache.serializer.ICacheSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class RedisCache<V> implements ICache<String, V> {
private final Logger logger = LoggerFactory.getLogger(RedisCache.class);
private String cacheName;
private RedisTemplate<String, Object> redisTemplate;
private ICacheSerializer serializer;
private long expireTime;
public RedisCache(String cacheName, RedisTemplate<String, Object> redisTemplate, ICacheSerializer serializer, long expireTime) {
this.cacheName = cacheName;
this.redisTemplate = redisTemplate;
this.serializer = serializer;
this.expireTime = expireTime;
}
@Override
public String store(V v) {
String key = generateKey();
this.store(key, v);
return key;
}
@Override
public void store(String key, V v) {
try {
long time1 = System.currentTimeMillis();
byte[] bytes = serializer.writeToByteArray(v);
if(bytes == null){
logger.debug("{}使用{}序列化 Key:{},Length:{},Timing:{}ms",cacheName,serializer.getName(),key,0,System.currentTimeMillis() - time1);
return;
}
logger.debug("{}使用{}序列化 Key:{},Length:{},Timing:{}ms",cacheName,serializer.getName(),key,bytes.length,System.currentTimeMillis() - time1);
time1 = System.currentTimeMillis();
redisTemplate.opsForValue().set(key, bytes, expireTime, TimeUnit.SECONDS);
logger.debug("{}写入redis Key:{},Length:{},Timing:{}ms",cacheName,key,bytes.length,System.currentTimeMillis() - time1);
} catch (Exception e) {
logger.error(cacheName+"使用"+serializer.getName() + "序列化保存缓存失败", e);
}
}
@Override
@SuppressWarnings("unchecked")
public V get(String s) {
try {
if (null == s) {
logger.error("RedisCache get with null key");
return null;
}
long time1 = System.currentTimeMillis();
byte[] bytes = (byte[]) redisTemplate.opsForValue().get(s);
if (null == bytes){
logger.debug("从redis读取Key:{},Length:{},Timing:{}ms",s,0,System.currentTimeMillis() - time1);
return null;
}
long time2 = System.currentTimeMillis();
logger.debug("从redis读取Key:{},Length:{},Timing:{}ms",s,bytes.length,System.currentTimeMillis() - time1 );
V v = serializer.readFromByteArray(bytes);
logger.debug("{}使用{}反序列化Key:{},Length:{},Timing:{} ms", cacheName,serializer.getName(),s,bytes.length, System.currentTimeMillis() - time2);
return v;
} catch (Exception e) {
logger.error(serializer.getName() + "反序列化失败", e);
if(e instanceof RuleExecuteException){
throw e;
}else{
throw new RuleExecuteException(serializer.getName() + "反序列化失败",e);
}
}
}
@Override
public void remove(String s) {
redisTemplate.delete(s);
}
@Override
public String generateKey() {
return cacheName + "-" + UUID.randomUUID();
}
@Override
public void keeplive(String key) {
if(key == null){
return;
}
redisTemplate.expire(key,expireTime,TimeUnit.SECONDS);
}
@Override
public void cleanup() {
logger.info("RedisCache not clean up .");
}
@Override
public boolean contains(String key) {
return redisTemplate.hasKey(key);
}
}
package com.brilliance.mda.support.cache.serializer;
public interface ICacheSerializer {
String getName();
<T> byte[] writeToByteArray(T obj);
<T> T readFromByteArray(byte[] bytes);
}
package com.brilliance.mda.support.cache.serializer;
import com.brilliance.mda.support.cache.serializer.impl.KryoSerializer;
public enum ICacheSerializerEnum {
Kryo("kryo", new KryoSerializer());
private String key;
private ICacheSerializer serializer;
ICacheSerializerEnum(String key, ICacheSerializer serializer) {
this.key = key;
this.serializer = serializer;
}
public static ICacheSerializer getSerializer(String key) {
for (ICacheSerializerEnum e : ICacheSerializerEnum.values()) {
if (e.key.equals(key))
return e.getSerializer();
}
return ICacheSerializerEnum.values()[0].getSerializer();
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public ICacheSerializer getSerializer() {
return serializer;
}
public void setSerializer(ICacheSerializer serializer) {
this.serializer = serializer;
}
}
package com.brilliance.mda.support.cache.serializer.impl;
import com.brilliance.mda.runtime.mda.*;
import com.brilliance.mda.runtime.mda.driver.MdaEnv;
import com.brilliance.mda.runtime.mda.impl.AbstractModule;
import com.brilliance.mda.runtime.mda.impl.ModuleList;
import com.brilliance.mda.support.cache.serializer.ICacheSerializer;
import com.esotericsoftware.kryo.kryo5.Kryo;
import com.esotericsoftware.kryo.kryo5.io.Input;
import com.esotericsoftware.kryo.kryo5.io.Output;
import com.esotericsoftware.kryo.kryo5.objenesis.strategy.StdInstantiatorStrategy;
import com.esotericsoftware.kryo.kryo5.util.DefaultInstantiatorStrategy;
import com.esotericsoftware.kryo.kryo5.util.Pool;
import com.google.common.io.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.lang.reflect.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicInteger;
public class KryoSerializer implements ICacheSerializer {
private static final Logger logger = LoggerFactory.getLogger(KryoSerializer.class);
private static final String NAME = "Kryo";
private static final String DEFAULT_ENCODING = StandardCharsets.UTF_8.toString();
private static final int bufferSize = 8192;
private static volatile Pool<Output> outputPool = new Pool<Output>(true, false, 50) {
@Override
protected Output create() {
return new Output(bufferSize, -1);
}
};
private static volatile Pool<Kryo> kryoPool = new Pool<Kryo>(true, false, 50) {
@Override
protected Kryo create() {
Kryo kryo = new Kryo();
kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
kryo.setReferences(true);
kryo.setRegistrationRequired(false);
return kryo;
}
};
@Override
public String getName() {
return NAME;
}
@Override
public <T> byte[] writeToByteArray(T obj) {
Output output = null;
Kryo kryo = null;
try {
output = outputPool.obtain();
kryo = kryoPool.obtain();
kryo.writeClassAndObject(output, obj);
byte[] buff = output.toBytes();
return buff;
} catch (Exception e) {
logger.error("Kryo序列化失败", e);
throw new RuleExecuteException("kryo 序列化异常!", e);
} finally {
if (kryo != null) {
kryoPool.free(kryo);
}
if (output != null) {
outputPool.free(output);
}
}
}
static AtomicInteger count = new AtomicInteger(0);
@Override
@SuppressWarnings("unchecked")
public <T> T readFromByteArray(byte[] bytes) {
Input input = new Input(bytes);
Kryo kryo = null;
try {
kryo = kryoPool.obtain();
long time2 = System.currentTimeMillis();
T t = (T) kryo.readClassAndObject(input);
if (t instanceof IContext) {
IContext context = (IContext) t;
IModule root = context.getRoot();
context.setEmitter(MdaEnv.getBean(IRuleEmitter.EMITTER_PRE + root.getClass().getSimpleName().toLowerCase(), IRuleEmitter.class));
moduleSetting(root);
logger.debug("bytes to module timing:{}ms", System.currentTimeMillis() - time2);
}
return t;
} catch (Exception e) {
logger.error("Kryo反序列化失败", e);
int i = count.incrementAndGet();
try {
File file = new File(MdaEnv.getRootPath(), "kryo_ex_" + i + ".ky");
Files.write(bytes, file);
} catch (Exception ex) {
logger.warn("", ex);
}
throw new RuleExecuteException("kryo反序列化异常!", e);
} finally {
if (kryo != null) {
kryoPool.free(kryo);
}
}
}
private void moduleSetting(IModule module) {
invokeSetArgumentMethod(module);
Field[] fields = module.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
Class<?> clazz = field.getType();
try {
Object o = field.get(module);
if (null == o) continue;
if (AbstractModule.class.isAssignableFrom(clazz)) {
moduleSetting((IModule) o);
} else if (ModuleList.class.isAssignableFrom(clazz)) {
fillModuleList(module, field, (ModuleList<?>) o);
}
} catch (IllegalAccessException ignored) {
}
}
}
private void invokeSetArgumentMethod(IModule module) {
try {
Method method = module.getClass().getMethod("setArgument");
method.invoke(module);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ignored) {
}
}
private void fillModuleList(IModule parentModule, Field field, ModuleList<?> moduleList) {
try {
Class<? extends ModuleList> moduleListClass = moduleList.getClass();
Field parentField = moduleListClass.getDeclaredField("_parent");
Field nameField = moduleListClass.getDeclaredField("_name");
Field pathField = moduleListClass.getDeclaredField("_path");
Field dataClassField = moduleListClass.getDeclaredField("dataClass");
Field moduleTypeField = moduleListClass.getDeclaredField("moduleType");
parentField.setAccessible(true);
nameField.setAccessible(true);
pathField.setAccessible(true);
dataClassField.setAccessible(true);
moduleTypeField.setAccessible(true);
parentField.set(moduleList, parentModule);
nameField.set(moduleList, field.getName());
String prefix = parentModule.getPath();
if (prefix == null || prefix.length() == 0 || prefix.equals(IBaseObject.separator)) {
pathField.set(moduleList, IBaseObject.separator + field.getName());
} else {
pathField.set(moduleList, prefix + IBaseObject.separator + field.getName());
}
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType) type;
Type[] actualTypeArguments = t.getActualTypeArguments();
if (null != actualTypeArguments && actualTypeArguments.length > 0) {
Class<?> aClass = (Class<?>) actualTypeArguments[0];
dataClassField.set(moduleList, aClass);
moduleTypeField.set(moduleList, aClass.getSimpleName().toLowerCase());
}
}
for (IModule module : moduleList) {
moduleSetting(module);
}
} catch (NoSuchFieldException | IllegalAccessException ignored) {
}
}
}
......@@ -12,6 +12,7 @@ public class TDAuthInfo implements IAuthInfo {
private IStream ddsStream;
private IStream keepAuthInfo;
public TDAuthInfo(){}
public TDAuthInfo(String userId) {
this.userId = userId;
......
......@@ -56,8 +56,6 @@
<slf4j.api.version>1.7.25</slf4j.api.version>
<spring.context.version>5.2.9.RELEASE</spring.context.version>
<fastjson.version>1.2.53</fastjson.version>
<ojdbc6.version>11.2.0.4</ojdbc6.version>
</properties>
<dependencyManagement>
......@@ -228,11 +226,6 @@
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc6</artifactId>
<version>${ojdbc6.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment