问题
最近看redis教程过程中,发现了直接将redisTemplate注入到ValueOperations,进行两个无关联类之间的注入的方式,甚是不解,遂百度。
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> string;
原理
原来在spring注入对象时,会进行判断。
如果你要实例化的对象和你的引用对象并不是同一种类型,也就是像redisTemplate和ValueOperations这样没有继承关系或接口实现关系,那么spring就会进行转换。
// 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());
}
}
用什么转换呢?Spring的editor,spring会去加载 ValueOperations+Editor,即ValueOperationsEditor的类。且此类必须要实现PropertyEditor接口。
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);
}
而在ValueOperations的包目录下确实会找到ValueOperationsEditor,该类继承的PropertyEditorSupport 类实现了PropertyEditor接口。
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 getValue的时候就能获取到DefaultValueOperations了。就可以将DefaultValueOperations注入到ValueOperations中去了。
总结
也就是说,如果想实现无关联类之间的注入,需要为被注入的类写一个Editor类,并实现PropertyEditor接口,重写setValue方法。