REDIS学習(4)spring boot redisTemplateのREDISの簡単なパッケージ、および参照パッケージの説明、およびシーケンス化の詳細な説明


総合1,2,3および現在、私たちが引用しているredisパッケージは
		
			org.springframework.boot
			spring-boot-starter-redis
		

追加後
参照パッケージは少なくとも
spring-boot-starter-redis-1.3.5.RELEASE.jar
spring-data-redis-1.6.4.RELEASE.jar
jedis-2.7.3.jar
三つのかばん
前の第3節と合わせてredisはSpringとともに汎用キャッシュインタフェースとして使用されています
このセクションで使用するredisTemplateは、データベースの操作に似ています.
@Service
public class RedisService {
	@Autowired
	RedisTemplate, ?> redisTemplate;
	/**        */
	public List> getClients(){
		return redisTemplate.getClientList();
	}
	/**        KV */
	public Long set(String key, String value, long seconds) {
		return redisTemplate.execute(c -> {
			c.set(key.getBytes(), value.getBytes());
			c.expire(key.getBytes(), seconds);
			return 1L;
		});
	}
	/**
	 *       KV
	 */
	public Long set(String key, String value) {
		return redisTemplate.execute(c -> {
			c.set(key.getBytes(), value.getBytes());
			return 1L;
		});
	}
	/**
	 * redis     
	 */
	public Long dbSize() {
		return redisTemplate.execute(c -> c.dbSize());
	}

	public String ping() {
		return redisTemplate.execute(c -> c.ping());
	}
	/**
	 *             
	 */
	public long flushDB() {
		return redisTemplate.execute(c -> {
			c.flushDb();
			return 1L;
		});
	}
	/**  redis         key*/
	public boolean exist(String key){
		return redisTemplate.execute(c->c.exists(key.getBytes()));
	}
	/**  redis      key*/
	public Set keys(String pattern){
		return redisTemplate.execute(c->c.keys(pattern.getBytes()).stream().map(this::getUTF).collect(Collectors.toSet()));
	}
	private String getUTF(byte[] data){
		try {
			return new String(data, "utf-8");
		} catch (UnsupportedEncodingException e) {
			LogCore.BASE.error("parse bytes err:{}", e);
			return null;
		}
	}
}

次の操作を行います.
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public long save(UserInfo usrInfo) {
		return redisTemplate.execute(c -> {
			RedisSerializer key_slz = redisTemplate.getKeySerializer();
			RedisSerializer slz = redisTemplate.getValueSerializer();
			LogCore.BASE.info("key_slz={},slz={}",key_slz.getClass().getSimpleName(),slz.getClass().getSimpleName());
			c.set(
					key_slz.serialize(usrInfo.getClass().getSimpleName() + ":" + usrInfo.no), 
					slz.serialize(usrInfo));
			return 1L;
		});
	}

	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public UserInfo get(String no) {
		return (UserInfo) redisTemplate.execute(c -> {
			RedisSerializer key_slz = redisTemplate.getKeySerializer();
			RedisSerializer slz = redisTemplate.getValueSerializer();
			return slz.deserialize(c.get(key_slz.serialize(UserInfo.class.getSimpleName() + ":" + no)));
		});
	}

前節によれば、RedisTemplateが指定されていない場合、spring redis cacheはjavaAPIのシーケンス化方式を選択してオブジェクトをシーケンス化することを知っています.このシーケンス化方式の性能は一般的に、後にフィールドを追加すると面倒になります.適切なシーケンス化方式はprotocol buffer、JSON、再帰的なバイナリバイトストリームを持つ方式などがあると思います.
次にRedisTempalteというクラスを詳細に解析し,StringRedisTemplateはRedisTemplateの唯一のサブクラスである.
このクラスは簡単で、私たちはこの方法に倣って自分のMyRedisTemplateを定義することができます.
[API]
public class StringRedisTemplate extends RedisTemplate {
	public StringRedisTemplate() {
		RedisSerializer stringSerializer = new StringRedisSerializer();
		setKeySerializer(stringSerializer);
		setValueSerializer(stringSerializer);
		setHashKeySerializer(stringSerializer);
		setHashValueSerializer(stringSerializer);
	}
	public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
		this();
		setConnectionFactory(connectionFactory);
		afterPropertiesSet();
	}

	protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
		return new DefaultStringRedisConnection(connection);
	}
}
では、子クラスの構築方法は、親クラスの非参照構築方法をデフォルトで呼び出すことに注意してください.
RedisTemplateのデフォルトでは、2つの一般的なシーケンス化クラスが定義されています.
private RedisSerializer> defaultSerializer = new JdkSerializationRedisSerializer();
及びprivate RedisSerializer stringSerializer=new StringRedisSerializer();
次の例ではkeyのシーケンス化方式を文字列として定義し、valueのシーケンス化にjacksonを使用します.
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

	@Bean
	public CacheManager cacheManager(RedisTemplate, ?> redisTemplate) {
		RedisCacheManager manager = new RedisCacheManager(redisTemplate);
		return manager;
	}

	@Bean
	public RedisTemplate, ?> redisTemplate(RedisConnectionFactory connectionFactory) {
		RedisTemplate template = new RedisTemplate();
		template.setConnectionFactory(connectionFactory);
		setMySerializer(template);
		template.afterPropertiesSet();
		LogCore.BASE.info("template{}" ,ReflectionToStringBuilder.toString(template, ToStringStyle.SHORT_PREFIX_STYLE));
		return template;
	}

	/**
	 *        
	 */
	private void setMySerializer(RedisTemplate template) {
		Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(
				Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		template.setKeySerializer(template.getStringSerializer());
		template.setValueSerializer(jackson2JsonRedisSerializer);
	}

	@Bean
	public KeyGenerator smpkeyGenerator() {
		return (target, method, params) -> {
			StringBuilder sb = new StringBuilder();
			sb.append(target.getClass().getSimpleName()).append(":");//        
			sb.append(Stream.of(params).map(String::valueOf).collect(Collectors.joining("_")));
			return sb.toString();
		};
	}
}

最後にSpring data redis定義のシーケンス化インタフェースとデフォルトのJDKシーケンス化のパッケージを見てみましょう.コードは比較的きれいで、そこから学ぶことができます.
 [API]
public interface RedisSerializer {
	byte[] serialize(T t) throws SerializationException;
	T deserialize(byte[] bytes) throws SerializationException;
}
[API]
public class JdkSerializationRedisSerializer implements RedisSerializer {

	private Converter serializer = new SerializingConverter();
	private Converter deserializer = new DeserializingConverter();

	public Object deserialize(byte[] bytes) {
		if (SerializationUtils.isEmpty(bytes)) {
			return null;
		}

		try {
			return deserializer.convert(bytes);
		} catch (Exception ex) {
			throw new SerializationException("Cannot deserialize", ex);
		}
	}

	public byte[] serialize(Object object) {
		if (object == null) {
			return SerializationUtils.EMPTY_ARRAY;
		}
		try {
			return serializer.convert(object);
		} catch (Exception ex) {
			throw new SerializationException("Cannot serialize", ex);
		}
	}
}

[API]
public interface Converter {
	T convert(S source);
}

[API]
public class SerializingConverter implements Converter {

	private final Serializer serializer;

	public SerializingConverter() {
		this.serializer = new DefaultSerializer();
	}

	public SerializingConverter(Serializer serializer) {
		Assert.notNull(serializer, "Serializer must not be null");
		this.serializer = serializer;
	}

	@Override
	public byte[] convert(Object source) {
		ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
		try  {
			this.serializer.serialize(source, byteStream);
			return byteStream.toByteArray();
		}
		catch (Throwable ex) {
			throw new SerializationFailedException("Failed to serialize object using " +
					this.serializer.getClass().getSimpleName(), ex);
		}
	}

}

[API]
public class DeserializingConverter implements Converter {

	private final Deserializer deserializer;

	public DeserializingConverter() {
		this.deserializer = new DefaultDeserializer();
	}

	public DeserializingConverter(ClassLoader classLoader) {
		this.deserializer = new DefaultDeserializer(classLoader);
	}
	public DeserializingConverter(Deserializer deserializer) {
		Assert.notNull(deserializer, "Deserializer must not be null");
		this.deserializer = deserializer;
	}

	@Override
	public Object convert(byte[] source) {
		ByteArrayInputStream byteStream = new ByteArrayInputStream(source);
		try {
			return this.deserializer.deserialize(byteStream);
		}
		catch (Throwable ex) {
			throw new SerializationFailedException("Failed to deserialize payload. " +
					"Is the byte array a result of corresponding serialization for " +
					this.deserializer.getClass().getSimpleName() + "?", ex);
		}
	}

}

[API]シーケンス化writeObject
public class DefaultSerializer implements Serializer {
	@Override
	public void serialize(Object object, OutputStream outputStream) throws IOException {
		if (!(object instanceof Serializable)) {
			throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
					"but received an object of type [" + object.getClass().getName() + "]");
		}
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
		objectOutputStream.writeObject(object);
		objectOutputStream.flush();
	}

}

[API]逆シーケンス化はクラスローダで
public class DefaultDeserializer implements Deserializer {

	private final ClassLoader classLoader;
	public DefaultDeserializer() {
		this.classLoader = null;
	}
	public DefaultDeserializer(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}
	@Override
	@SuppressWarnings("resource")
	public Object deserialize(InputStream inputStream) throws IOException {
		ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, this.classLoader);
		try {
			return objectInputStream.readObject();
		}
		catch (ClassNotFoundException ex) {
			throw new NestedIOException("Failed to deserialize object type", ex);
		}
	}

}