今天看到Spring操作redis 是可以将redisTemplate注入到ValueOperations,避免了ValueOperations
@Resource(name = "redisTemplate") private ValueOperationsvOps;
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'
我们完成ClassAEditor
public class ClassAEditor extends PropertyEditorSupport{ public void setValue(Object value) { super.setValue(((ClassB)value).getA()); } }
判断略去不写。
运行程序,得到正确结果
非常有意思的一个细节,工厂模式的一种体现。