今天看到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'
我們完成ClassAEditor
public class ClassAEditor extends PropertyEditorSupport{ public void setValue(Object value) { super.setValue(((ClassB)value).getA()); } }
判斷略去不寫。
運行程序,得到正確結果
非常有意思的一個細節,工廠模式的一種體現。