Java 从spring模板连接到加密的Redis群集
我正在尝试从spring boot连接到一个加密的在途ElastiCache集群,以用于会话存储库。我有适用于未加密集群的代码,但在启用ssl时无法使其工作。这是我的密码Java 从spring模板连接到加密的Redis群集,java,spring-boot,ssl,spring-data-redis,amazon-elasticache,Java,Spring Boot,Ssl,Spring Data Redis,Amazon Elasticache,我正在尝试从spring boot连接到一个加密的在途ElastiCache集群,以用于会话存储库。我有适用于未加密集群的代码,但在启用ssl时无法使其工作。这是我的密码 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframe
import org.springframework.beans.factory.annotation.Autowired;
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;
import org.springframework.session.ExpiringSession;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;
import org.springframework.session.web.http.SessionRepositoryFilter;
@Configuration
@EnableRedisHttpSession
@ConditionalOnProperty(value = "spring.session.enabled", havingValue = "true")
public class RedisSessionConfig extends RedisHttpSessionConfiguration {
private final String NAMESPACE = "myname";
public RedisSessionConfig() {
// when extending RedisHttpSessionConfiguration to override the repository filter
// we need to manually set the namespace
this.setRedisNamespace(NAMESPACE);
}
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
@Bean
@Override
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
return super.springSessionRepositoryFilter(new SafeDeserializationRepository<>(sessionRepository, redisTemplate, NAMESPACE));
}
}
有人知道怎么做吗?所以我不得不添加自己的LettuceConnectionFactory实现,然后因为连接速度特别慢,我还需要实现自己的连接池 代码如下:
@Configuration
class MyLettuceConnectionFactory extends LettuceConnectionFactory {
@Autowired
public MyLettuceConnectionFactory(
@Value("${redis-configuration.clusterEndpoint}") String clusterNodes,
@Value("${redis-configuration.port}") int port,
@Value("${redis-configuration.ssl}") boolean ssl,
@Value("${redis-configuration.pool.minimumIdle}") int minIdle,
@Value("${redis-configuration.pool.maximumIdle}") int maxIdle
) {
super(new MyLettucePool(clusterNodes, port, ssl, minIdle, maxIdle));
this.setUseSsl(ssl);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
DirectFieldAccessor accessor = new DirectFieldAccessor(this);
AbstractRedisClient client = (AbstractRedisClient) accessor.getPropertyValue("client");
if(client instanceof RedisClusterClient){
RedisClusterClient clusterClient = (RedisClusterClient) client;
clusterClient.setOptions(ClusterClientOptions.builder().validateClusterNodeMembership(false).build());
}
}
}
对于我的自定义连接池:
public class MyLettucePool implements LettucePool {
private RedisClusterClient client;
private int dbIndex=0;
private GenericObjectPool<StatefulConnection<byte[], byte[]>> internalPool;
public MyLettucePool(String clusterEndpoint, int port, boolean useSsl, int minIdle, int maxIdle) {
RedisURI uri = new RedisURI();
uri.setSsl(useSsl);
uri.setPort(port);
uri.setHost(clusterEndpoint);
GenericObjectPoolConfig<StatefulConnection<byte[], byte[]>> config = new GenericObjectPoolConfig<>();
config.setMinIdle(minIdle);
config.setMaxIdle(maxIdle);
this.client = RedisClusterClient.create(uri);
this.client.setOptions(ClusterClientOptions.builder().autoReconnect(true).validateClusterNodeMembership(false).build());
this.internalPool = ConnectionPoolSupport.createGenericObjectPool(() -> this.client.connect(new ByteArrayCodec()), new GenericObjectPoolConfig());
}
@Override
public AbstractRedisClient getClient() {
return this.client;
}
@Override
@SuppressWarnings("unchecked")
public StatefulConnection<byte[], byte[]> getResource() {
try {
return internalPool.borrowObject();
} catch (Exception e) {
throw new PoolException("Could not get a resource from the pool", e);
}
}
@Override
public void returnBrokenResource(final StatefulConnection<byte[], byte[]> resource) {
try {
internalPool.invalidateObject(resource);
} catch (Exception e) {
throw new PoolException("Could not invalidate the broken resource", e);
}
}
@Override
public void returnResource(final StatefulConnection<byte[], byte[]> resource) {
try {
internalPool.returnObject(resource);
} catch (Exception e) {
throw new PoolException("Could not return the resource to the pool", e);
}
}
@Override
public void destroy() {
try {
client.shutdown();
internalPool.close();
} catch (Exception e) {
throw new PoolException("Could not destroy the pool", e);
}
}
公共类MyLettucePool实现了LettucePool{
私有再聚集客户端;
私有int-dbIndex=0;
私有GenericObject池内部池;
公共MyLettucePool(字符串clusterEndpoint、int-port、布尔usesl、int-minIdle、int-maxIdle){
RedisURI=新的RedisURI();
setSsl(usesl);
uri.setPort(端口);
setHost(clusterEndpoint);
GenericObjectPoolConfig=新的GenericObjectPoolConfig();
config.setMinIdle(minIdle);
config.setMaxIdle(maxIdle);
this.client=RedisClusterClient.create(uri);
this.client.setOptions(ClusterClientOptions.builder().autoReconnect(true).validateClusterNodeMembership(false).build());
this.internalPool=ConnectionPoolSupport.createGenericObjectPool(()->this.client.connect(new ByteArrayCodec()),new GenericObjectPoolConfig());
}
@凌驾
公共抽象RedisClient getClient(){
将此文件退还给客户;
}
@凌驾
@抑制警告(“未选中”)
public StatefulConnection getResource(){
试一试{
返回internalPool.borrowObject();
}捕获(例外e){
抛出新的PoolException(“无法从池中获取资源”,e);
}
}
@凌驾
public void returnbrokernResource(最终状态连接资源){
试一试{
internalPool.invalidateObject(资源);
}捕获(例外e){
抛出新的PoolException(“无法使中断的资源无效”,e);
}
}
@凌驾
public void returnResource(最终状态连接资源){
试一试{
returnObject(资源);
}捕获(例外e){
抛出新的PoolException(“无法将资源返回池”,e);
}
}
@凌驾
公共空间销毁(){
试一试{
client.shutdown();
internalPool.close();
}捕获(例外e){
抛出新的PoolException(“无法销毁池”,e);
}
}
感谢您提供此解决方案,我也面临同样的问题。
public class MyLettucePool implements LettucePool {
private RedisClusterClient client;
private int dbIndex=0;
private GenericObjectPool<StatefulConnection<byte[], byte[]>> internalPool;
public MyLettucePool(String clusterEndpoint, int port, boolean useSsl, int minIdle, int maxIdle) {
RedisURI uri = new RedisURI();
uri.setSsl(useSsl);
uri.setPort(port);
uri.setHost(clusterEndpoint);
GenericObjectPoolConfig<StatefulConnection<byte[], byte[]>> config = new GenericObjectPoolConfig<>();
config.setMinIdle(minIdle);
config.setMaxIdle(maxIdle);
this.client = RedisClusterClient.create(uri);
this.client.setOptions(ClusterClientOptions.builder().autoReconnect(true).validateClusterNodeMembership(false).build());
this.internalPool = ConnectionPoolSupport.createGenericObjectPool(() -> this.client.connect(new ByteArrayCodec()), new GenericObjectPoolConfig());
}
@Override
public AbstractRedisClient getClient() {
return this.client;
}
@Override
@SuppressWarnings("unchecked")
public StatefulConnection<byte[], byte[]> getResource() {
try {
return internalPool.borrowObject();
} catch (Exception e) {
throw new PoolException("Could not get a resource from the pool", e);
}
}
@Override
public void returnBrokenResource(final StatefulConnection<byte[], byte[]> resource) {
try {
internalPool.invalidateObject(resource);
} catch (Exception e) {
throw new PoolException("Could not invalidate the broken resource", e);
}
}
@Override
public void returnResource(final StatefulConnection<byte[], byte[]> resource) {
try {
internalPool.returnObject(resource);
} catch (Exception e) {
throw new PoolException("Could not return the resource to the pool", e);
}
}
@Override
public void destroy() {
try {
client.shutdown();
internalPool.close();
} catch (Exception e) {
throw new PoolException("Could not destroy the pool", e);
}
}