今天看到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());
}
}
判断略去不写。
运行程序,得到正确结果
非常有意思的一个细节,工厂模式的一种体现。