Bootstrap

关于@Resource(name = “redisTemplate”)注入问题

依赖dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!-- 以上为springboot启动器,springData启动器(Redistemplate) -->

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- 测试类启动器 -->

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>
<!-- 方便为RedisTemplate的key-value做序列化操作 -->

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 数据库连接 -->

解决

1.关于 @Resource(name = “redisTemplate”) 为何可以为 ValueOperations 类型注入实体

@Autowired
private RedisTemplate redisTemplate;

@Resource(name = "redisTemplate")
private ValueOperations<String, String> strOperation;

可以延伸为实例化的对象和你的引用对象并不是同一种类型的问题。也就是如redisTemplate和ValueOperations一般不是父子关系或接口实现关系,那么spring就会进行转换。转换的方式就是通过Spring的Editor做的。
在项目启动过程中,spring会进行实例化和注入操作
在org.springframework.beans.factory.support.AbstractBeanFactory 类中的 doGetBean 方法中,实际上是调用了 org.springframework.beans.TypeConverterDelegate 类中convertIfNecessary方法,待进入以下步骤来处理实例化类型与引用类型不同的问题

// Value not of required type?
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
	if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
			convertedValue instanceof String) {
		TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
		if (elementTypeDesc != null) {
			Class<?> elementType = elementTypeDesc.getType();
			if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
				convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
			}
		}
	}
	if (editor == null) {
	//此处去获取相关Editor,在该问题中为ValueOperationsEditor类
		editor = findDefaultEditor(requiredType);
	}
	convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}

findDefaultEditor方法是获取相关Editor,在该问题中为ValueOperationsEditor的类。且此类必须要实现PropertyEditor接口。

doConvertValue的作用

Object convertedValue = newValue;
if (editor != null && !(convertedValue instanceof String)) {
	try {
		editor.setValue(convertedValue);
		Object newConvertedValue = editor.getValue();
		if (newConvertedValue != convertedValue) {
			convertedValue = newConvertedValue;
			// Reset PropertyEditor: It already did a proper conversion.
			// Don't use it again for a setAsText call.
			editor = null;
		}
	}
	catch (Exception ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("PropertyEditor [" + editor.getClass().getName() + "] does not support setValue call", ex);
		}
		// Swallow and proceed.
	}
}

1).先通过editor.setValue将实例化对象通过ValueOperationsEditor的setValue方法保存替换掉。ValueOperationsEditor类中的setValue方法已被重写,实例化对象通过符合条件的RedisOperations实例的opsForValue方法保存为ValueOperations类型了。而实现了RedisOperations接口的opsForValue方法只有RedisTemplate类。

public void setValue(Object value) {
	if (value instanceof RedisOperations) {
		super.setValue(((RedisOperations) value).opsForValue());
	} else {
		throw new IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class);
	}
}

2).通过editor.getValue()再获取该值。则可以注入。

参考点击这里.

入行不久,个人理解,方便记录
;