|
一 简介
ValueOperations和HashOperations和都是操作对redis进行数据操作的工具类。
二 区别
REDISTEMPLATE如何注入到VALUEOPERATIONS
今天看到Spring操作redis 是可以将redisTemplate注入到ValueOperations,避免了ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue(); 这样来获取ValueOperations;
@Resource(name = "redisTemplate") private ValueOperations<String, Object> vOps;redisTemplate并不是ValueOperations的实现类,这两个在继承上毫无联系的两个类是如何注入的呢。
后来查doGetBean()的代码才发现有一段以前没有详细的去看。
// Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } }如果你要实例化的对象和你的引用对象并不是同一种类型,也就是如redisTemplate和ValueOperations一般不是父子关系或接口实现关系,那么spring就会进行转换。
用什么转换呢?Spring的editor。
String editorName = targetType.getName() + "Editor"; try { Class<?> editorClass = cl.loadClass(editorName); if (!PropertyEditor.class.isAssignableFrom(editorClass)) { if (logger.isWarnEnabled()) { logger.warn("Editor class [" + editorName + "] does not implement [java.beans.PropertyEditor] interface"); } unknownEditorTypes.add(targetType); return null; } return (PropertyEditor) instantiateClass(editorClass); }spring会去加载 ValueOperations+Editor,即ValueOperationsEditor的类。且此类必须要实现PropertyEditor接口。
而我们在ValueOperations的包目录下确实会找到ValueOperationsEditor。
class ValueOperationsEditor extends PropertyEditorSupport { public void setValue(Object value) { if (value instanceof RedisOperations) { super.setValue(((RedisOperations) value).opsForValue()); } else { throw new java.lang.IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); } } }这个类非常简单,它重写了setValue方法,将redisTemplate中的opsForValue()返回值set进去,而opsForValue()返回值就是继承了ValueOperations的DefaultValueOperations。
这样我们用editor get value的时候就能获取到DefaultValueOperations了。就可以将DefaultValueOperations注入到ValueOperations中去了。
做个实验,写两个类
public class ClassA { private String msg; public ClassA(String msg){ this.msg=msg; } public void hi(){ System.out.println(msg); } }
@Component public class ClassB { public ClassA getA(){ return new ClassA("this is A from B"); } }类B有个方法可以获取A类实例,我们将此注入到A对象中。
public class EditorTest extends BaseJunitTest{ @Resource(name="classB") private ClassA a; @Test public void test(){ a.hi(); } }BaseJunitTest配置了一些spring的XML配置文件 不需要管它。
此时我们还需要写一个ClassAEditor类。如果没有editor类的话当然会注入不了 并抛出一个异常
Bean named 'classB' is expected to be of type 'xxx.test.ClassA' but was actually of type 'xxx.test.ClassB'
我们完成ClassAEditorpublic class ClassAEditor extends PropertyEditorSupport{ public void setValue(Object value) { super.setValue(((ClassB)value).getA()); } }判断略去不写。
运行程序,得到正确结果
非常有意思的一个细节,工厂模式的一种体现。
分类: Spring转载于:https://www.cnblogs.com/kelelipeng/p/11236916.html
ValueOperations 源码 解析
/** *设置 key 的值为 value *如果key不存在添加key 保存值为value *如果key存在则对value进行覆盖 */ void set(K key, V value); /** * 设置 key 的值为 value * 其它规则与 set(K key, V value)一样 * @param key 不能为空 * @param value 设置的值 * @param timeout 设置过期的时间 * @param unit 时间单位。不能为空 * @see <a href="http://redis.io/commands/setex">Redis Documentation: SETEX</a> */ void set(K key, V value, long timeout, TimeUnit unit); /** *如果key不存在,则设置key 的值为 value. 存在则不设置 *设置成功返回true 失败返回false * @param key key不能为空 * @param value 设置的值 */ Boolean setIfAbsent(K key, V value); /** * 把一个map的键值对添加到redis中,key-value 对应着 key value。如果key已经存在就覆盖, * @param map不能为null 为null抛出空指针异常 可以为空集合 */ void multiSet(Map<? extends K, ? extends V> map); /** * 把一个map的键值对添加到redis中,key-value 对应着 key value。 当且仅当map中的所有key都 * 不存在的时候,添加成功返回 true,否则返回false. * @param map map不能为空 可以为empty */ Boolean multiSetIfAbsent(Map<? extends K, ? extends V> map); /** * 根据 key 获取对应的value 如果key不存在则返回null * @param key 不能为null */ V get(Object key); /** * 设置key的值为value 并返回旧值。 如果key不存在返回为null * @param key 不能为null */ V getAndSet(K key, V value); /** * 根据提供的key集合按顺序获取对应的value值 * @param 集合不能为null 可以为empty 集合 */ List<V> multiGet(Collection<K> keys); /** * 为key 的值加上 long delta. 原来的值必须是能转换成Integer类型的。否则会抛出异常。 * @param key 不能为null * @param delta 需要增加的值 */ Long increment(K key, long delta); /** * 为key 的值加上 double delta. 原来的值必须是能转换成Integer类型的。否则会抛出异常。 * 添加double后不能再加整数。已经无法在转换为Integer * @param key 不能为null * @param 增加的值 */ Double increment(K key, double delta); /** * 为 key的值末尾追加 value 如果key不存在就直接等于 set(K key, V value) * * @param key 不能为null * @param value 追加的值 * @see <a href="http://redis.io/commands/append">Redis Documentation: APPEND</a> */ Integer append(K key, String value); /** * 获取key 值从 start位置开始到end位置结束。 等于String 的 subString 前后闭区间 *0 -1 整个key的值 *-4 -1 从尾部开始往前截长度为4 * @param key 不能为null * @param start 起始位置 * @param end 结束位置 * @see <a href="http://redis.io/commands/getrange">Redis Documentation: GETRANGE</a> */ String get(K key, long start, long end); /** * 将value从指定的位置开始覆盖原有的值。如果指定的开始位置大于字符串长度,先补空格在追加。 * 如果key不存在,则等于新增。长度大于0则先补空格 set("key10", "abc", 3) 得到结果为: * 3空格 +"abc" * @param key 不能为null * @param value 值 * @param offset 开始的位置 */ void set(K key, V value, long offset); /** * 获取key的value的长度。key不存在返回0 * @param key 不能为空 */ Long size(K key); /** * 设置key的值偏移量为offset的bit位上的值为0或者1.true:1 false:0 * * @param key 不能为空 * @param offset 偏移量 * @param value true or false */ Boolean setBit(K key, long offset, boolean value); /** * 获取key的值偏移量offset的bit位的值。 返回true or false * * @param key 不能为空 * @param offset 偏移量 * 可以通过redis的 JedisConverters 对布尔结果进行转换 */ Boolean getBit(K key, long offset);
今天看到Spring操作redis 是可以将redisTemplate注入到ValueOperations,避免了ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue(); 这样来获取ValueOperations;
@Resource(name = "redisTemplate") private ValueOperations<String, Object> vOps;redisTemplate并不是ValueOperations的实现类,这两个在继承上毫无联系的两个类是如何注入的呢。
后来查doGetBean()的代码才发现有一段以前没有详细的去看。
// Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } }如果你要实例化的对象和你的引用对象并不是同一种类型,也就是如redisTemplate和ValueOperations一般不是父子关系或接口实现关系,那么spring就会进行转换。
用什么转换呢?Spring的editor。
String editorName = targetType.getName() + "Editor"; try { Class<?> editorClass = cl.loadClass(editorName); if (!PropertyEditor.class.isAssignableFrom(editorClass)) { if (logger.isWarnEnabled()) { logger.warn("Editor class [" + editorName + "] does not implement [java.beans.PropertyEditor] interface"); } unknownEditorTypes.add(targetType); return null; } return (PropertyEditor) instantiateClass(editorClass); }spring会去加载 ValueOperations+Editor,即ValueOperationsEditor的类。且此类必须要实现PropertyEditor接口。
而我们在ValueOperations的包目录下确实会找到ValueOperationsEditor。
class ValueOperationsEditor extends PropertyEditorSupport { public void setValue(Object value) { if (value instanceof RedisOperations) { super.setValue(((RedisOperations) value).opsForValue()); } else { throw new java.lang.IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); } } }这个类非常简单,它重写了setValue方法,将redisTemplate中的opsForValue()返回值set进去,而opsForValue()返回值就是继承了ValueOperations的DefaultValueOperations。
这样我们用editor get value的时候就能获取到DefaultValueOperations了。就可以将DefaultValueOperations注入到ValueOperations中去了。
做个实验,写两个类
public class ClassA { private String msg; public ClassA(String msg){ this.msg=msg; } public void hi(){ System.out.println(msg); } }
@Component public class ClassB { public ClassA getA(){ return new ClassA("this is A from B"); } }类B有个方法可以获取A类实例,我们将此注入到A对象中。
public class EditorTest extends BaseJunitTest{ @Resource(name="classB") private ClassA a; @Test public void test(){ a.hi(); } }BaseJunitTest配置了一些spring的XML配置文件 不需要管它。
此时我们还需要写一个ClassAEditor类。如果没有editor类的话当然会注入不了 并抛出一个异常
Bean named 'classB' is expected to be of type 'xxx.test.ClassA' but was actually of type 'xxx.test.ClassB'
我们完成ClassAEditorpublic class ClassAEditor extends PropertyEditorSupport{ public void setValue(Object value) { super.setValue(((ClassB)value).getA()); } }判断略去不写。
运行程序,得到正确结果
非常有意思的一个细节,工厂模式的一种体现。
转载于:https://www.cnblogs.com/tangyuanyuan/p/8067923.html