[feat] 新增Redis多数据源插件 magic-api-plugin-dynamic-redis
This commit is contained in:
parent
662646a8c2
commit
f46d9c77e3
@ -4,10 +4,11 @@ package org.ssssssss.magicapi.redis;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
@ -22,14 +23,16 @@ import java.util.Map;
|
||||
@Slf4j
|
||||
@EnableAsync
|
||||
@Configuration
|
||||
@DependsOn("redisInstanceFactory")
|
||||
@ConfigurationProperties(prefix = "magic-api.redis")
|
||||
@Import({MagicRedisConfiguration.class,RedisInstanceFactory.class,MagicRedisConfiguration.class})
|
||||
@Import({RedisInstanceFactory.class,MagicRedisConfiguration.class,})
|
||||
public class MagicDynamicRedisAutoConfig implements InitializingBean {
|
||||
|
||||
@Getter
|
||||
public static String primary;
|
||||
|
||||
@Autowired
|
||||
public RedisInstanceFactory redisInstanceFactory;
|
||||
|
||||
@Getter
|
||||
private static Map<String, MagicRedisProperties> dynamic = new LinkedHashMap<>();
|
||||
|
||||
@ -37,25 +40,26 @@ public class MagicDynamicRedisAutoConfig implements InitializingBean {
|
||||
public void afterPropertiesSet() {
|
||||
Assert.isNotNull(primary, "Redis未设置默认库");
|
||||
dynamic.forEach((redisName, redisProperty) -> {
|
||||
// 构建Redis服务
|
||||
RedisInstanceFactory.getInstance().buildRedisTemplate(redisName, redisProperty);
|
||||
redisInstanceFactory.buildRedisTemplate(redisName, redisProperty);
|
||||
});
|
||||
log.info("[动态Redis]--共创建Redis[{}]个", dynamic.size());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public StringRedisTemplate stringRedisTemplate() {
|
||||
MagicRedisProperties redisProperties = dynamic.get(primary);
|
||||
RedisConnectionFactory connectionFactory = RedisInstanceFactory.getInstance().buildLettuceConnectionFactory(primary, redisProperties);
|
||||
RedisConnectionFactory connectionFactory = redisInstanceFactory.buildLettuceConnectionFactory(primary, redisProperties);
|
||||
StringRedisTemplate template = new StringRedisTemplate();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RedisTemplate<Object, Object> redisTemplate() {
|
||||
MagicRedisProperties redisProperties = dynamic.get(primary);
|
||||
RedisConnectionFactory connectionFactory = RedisInstanceFactory.getInstance().buildLettuceConnectionFactory(primary, redisProperties);
|
||||
RedisConnectionFactory connectionFactory = redisInstanceFactory.buildLettuceConnectionFactory(primary, redisProperties);
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
return template;
|
||||
|
||||
@ -21,7 +21,7 @@ public class MagicRedisProperties {
|
||||
/**
|
||||
* 连接类型
|
||||
*/
|
||||
private RedisConnectionType type;
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* redis主机地址,ip:port,多个用逗号(,)分隔
|
||||
|
||||
@ -1,20 +1,8 @@
|
||||
package org.ssssssss.magicapi.redis;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisPipelineException;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.ssssssss.magicapi.core.annotation.MagicModule;
|
||||
import org.ssssssss.magicapi.utils.Assert;
|
||||
import org.ssssssss.script.functions.DynamicMethod;
|
||||
import org.ssssssss.script.reflection.JavaReflection;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* redis 多数据源插件模块
|
||||
@ -23,12 +11,10 @@ import java.util.*;
|
||||
*/
|
||||
@MagicModule("dynamicRedis")
|
||||
@Slf4j
|
||||
public class RedisDynamicModule implements DynamicMethod {
|
||||
public class RedisDynamicModule {
|
||||
|
||||
private final RedisInstanceFactory redisInstanceFactory;
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
private boolean isRedisson;
|
||||
|
||||
public RedisDynamicModule(RedisInstanceFactory redisInstanceFactory) {
|
||||
this.redisInstanceFactory = redisInstanceFactory;
|
||||
@ -37,110 +23,19 @@ public class RedisDynamicModule implements DynamicMethod {
|
||||
/**
|
||||
* 序列化
|
||||
*/
|
||||
public RedisDynamicModule name(String name) {
|
||||
this.redisTemplate = redisInstanceFactory.getRedisTemplate(name, false);
|
||||
Assert.isTrue(redisTemplate==null, "当前没有配置redis " + name);
|
||||
this.isRedisson = Objects.equals("org.redisson.spring.data.connection.RedissonConnectionFactory", this.redisTemplate.getConnectionFactory().getClass().getName());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 序列化
|
||||
*/
|
||||
private byte[] serializer(Object value) {
|
||||
if (value == null || value instanceof String) {
|
||||
return redisTemplate.getStringSerializer().serialize((String) value);
|
||||
}
|
||||
return serializer(value.toString());
|
||||
}
|
||||
|
||||
private Object serializerForRedisson(Object value) {
|
||||
if (value == null || JavaReflection.isPrimitiveAssignableFrom(value.getClass(), value.getClass())) {
|
||||
return value;
|
||||
}
|
||||
return serializer(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object deserialize(Object value) {
|
||||
if (value != null) {
|
||||
if (value instanceof byte[]) {
|
||||
return this.redisTemplate.getStringSerializer().deserialize((byte[]) value);
|
||||
}
|
||||
if (value instanceof List) {
|
||||
List<Object> valueList = (List<Object>) value;
|
||||
List<Object> resultList = new ArrayList<>(valueList.size());
|
||||
for (Object val : valueList) {
|
||||
resultList.add(deserialize(val));
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
Map<Object, Object> map = (Map<Object, Object>) value;
|
||||
LinkedHashMap<Object, Object> newMap = new LinkedHashMap<>(map.size());
|
||||
map.forEach((key, val) -> newMap.put(deserialize(key), deserialize(val)));
|
||||
return newMap;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令
|
||||
*
|
||||
* @param methodName 命令名称
|
||||
* @param parameters 命令参数
|
||||
*/
|
||||
@Override
|
||||
public Object execute(String methodName, List<Object> parameters) {
|
||||
return this.redisTemplate.execute(connection -> {
|
||||
Object result;
|
||||
if (isRedisson) {
|
||||
result = executeForRedisson(((DefaultStringRedisConnection) connection).getDelegate(), methodName, parameters);
|
||||
public RedisTemplate<?, ?> of(String name) {
|
||||
RedisTemplate<?, ?> redisTemplate = redisInstanceFactory.getRedisTemplate(name, true);
|
||||
if (redisTemplate!=null){
|
||||
log.info("使用redis {}", name);
|
||||
}else {
|
||||
byte[][] params = new byte[parameters.size()][];
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
params[i] = serializer(parameters.get(i));
|
||||
log.error("当前没有配置redis {}", name);
|
||||
}
|
||||
result = connection.execute(methodName, params);
|
||||
}
|
||||
return deserialize(result);
|
||||
}, isRedisson || this.redisTemplate.isExposeConnection());
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
private Object executeForRedisson(RedisConnection connection, String command, List<Object> parameters) {
|
||||
Method[] methods = connection.getClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (method.getName().equalsIgnoreCase(command) && Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == parameters.size()) {
|
||||
try {
|
||||
Object ret = this.execute(connection, method, parameters);
|
||||
if (ret instanceof String) {
|
||||
return ((String) ret).getBytes();
|
||||
}
|
||||
return ret;
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (connection.isPipelined()) {
|
||||
throw new RedisPipelineException(e);
|
||||
public RedisTemplate<?, ?> name(String name) {
|
||||
return of(name);
|
||||
}
|
||||
|
||||
throw new InvalidDataAccessApiUsageException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private Object execute(RedisConnection connection, Method method, List<Object> parameters) {
|
||||
if (method.getParameterTypes().length > 0 && method.getParameterTypes()[0] == byte[][].class) {
|
||||
return ReflectionUtils.invokeMethod(method, connection, parameters.stream().map(this::serializer).toArray(byte[][]::new));
|
||||
} else if (parameters.size() == 0) {
|
||||
return ReflectionUtils.invokeMethod(method, connection);
|
||||
}
|
||||
return ReflectionUtils.invokeMethod(method, connection, parameters.stream().map(this::serializerForRedisson).toArray());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -50,15 +50,7 @@ public class RedisInstanceFactory implements ApplicationContextAware {
|
||||
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
private RedisInstanceFactory() {
|
||||
}
|
||||
|
||||
public static class RedisFactoryLoader {
|
||||
private static final RedisInstanceFactory INSTANCE = new RedisInstanceFactory();
|
||||
}
|
||||
|
||||
public static RedisInstanceFactory getInstance() {
|
||||
return RedisFactoryLoader.INSTANCE;
|
||||
public RedisInstanceFactory() {
|
||||
}
|
||||
|
||||
public RedisTemplate<?, ?> getRedisTemplate(String redisName, boolean isStringRedisTemplate) {
|
||||
@ -83,7 +75,7 @@ public class RedisInstanceFactory implements ApplicationContextAware {
|
||||
* 创建 ConnectionFactory
|
||||
*/
|
||||
public RedisConnectionFactory buildLettuceConnectionFactory(String redisName, MagicRedisProperties redisProperties) {
|
||||
String redisClientName = getRedisTemplateName(redisName, false);
|
||||
String redisClientName = redisName+"RedisConnectionFactory";
|
||||
if (applicationContext.containsBean(redisClientName)) {
|
||||
return getBean(redisClientName);
|
||||
}
|
||||
@ -115,7 +107,7 @@ public class RedisInstanceFactory implements ApplicationContextAware {
|
||||
.poolConfig(poolConfig)
|
||||
.build();
|
||||
LettuceConnectionFactory lettuceConnectionFactory = null;
|
||||
RedisConnectionType connectionType = redisProperties.getType();
|
||||
RedisConnectionType connectionType = RedisConnectionType.match(redisProperties.getType());
|
||||
if (RedisConnectionType.SENTINEL.equals(connectionType)) {
|
||||
lettuceConnectionFactory = new LettuceConnectionFactory(buildSentinelConfig(redisProperties), clientConfig);
|
||||
} else if (RedisConnectionType.CLUSTER.equals(connectionType)) {
|
||||
|
||||
@ -1 +1,2 @@
|
||||
org.ssssssss.magicapi.redis.MagicRedisConfiguration
|
||||
org.ssssssss.magicapi.redis.RedisInstanceFactory
|
||||
org.ssssssss.magicapi.redis.MagicDynamicRedisAutoConfig
|
||||
@ -18,6 +18,7 @@
|
||||
<module>magic-api-plugin-swagger</module>
|
||||
<module>magic-api-plugin-springdoc</module>
|
||||
<module>magic-api-plugin-redis</module>
|
||||
<module>magic-api-plugin-dynamic-redis</module>
|
||||
<module>magic-api-plugin-mongo</module>
|
||||
<module>magic-api-plugin-elasticsearch</module>
|
||||
<module>magic-api-plugin-cluster</module>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user