类org.springframework.beans.factory.support.AbstractBeanFactory
方法T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)

这里requiredType是获取的实例要转换成的类型,转换通过org.springframework.beans.TypeConverter进行。

if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
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());
}
}

类org.springframework.beans.TypeConverterDelegate

TypeConverter调用java.beans.PropertyEditor。

public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException { Object convertedValue = newValue; // Custom editor for this type?
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName); ConversionFailedException firstAttemptEx = null; // No custom editor but custom ConversionService specified?
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && convertedValue != null && typeDescriptor != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
TypeDescriptor targetTypeDesc = typeDescriptor;
if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
try {
return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
}
catch (ConversionFailedException ex) {
// fallback to default conversion logic below
firstAttemptEx = ex;
}
}
} // Value not of required type?
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
if (editor == null) {
editor = findDefaultEditor(requiredType); // redis进入的是此分支路径
}
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
} boolean standardConversion = false; if (requiredType != null) {
// Try to apply some standard type conversion rules if appropriate. if (convertedValue != null) {
if (Object.class.equals(requiredType)) {
return (T) convertedValue;
}
if (requiredType.isArray()) {
// Array required -> apply appropriate conversion of elements.
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
}
else if (convertedValue instanceof Collection) {
// Convert elements to target type, if determined.
convertedValue = convertToTypedCollection(
(Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
else if (convertedValue instanceof Map) {
// Convert keys and values to respective target type, if determined.
convertedValue = convertToTypedMap(
(Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
convertedValue = Array.get(convertedValue, 0);
standardConversion = true;
}
if (String.class.equals(requiredType) && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
// We can stringify any primitive value...
return (T) convertedValue.toString();
}
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
if (firstAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
try {
Constructor<T> strCtor = requiredType.getConstructor(String.class);
return BeanUtils.instantiateClass(strCtor, convertedValue);
}
catch (NoSuchMethodException ex) {
// proceed with field lookup
if (logger.isTraceEnabled()) {
logger.trace("No String constructor found on type [" + requiredType.getName() + "]", ex);
}
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", ex);
}
}
}
String trimmedValue = ((String) convertedValue).trim();
if (requiredType.isEnum() && "".equals(trimmedValue)) {
// It's an empty enum identifier: reset the enum value to null.
return null;
}
convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
standardConversion = true;
}
} if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
if (firstAttemptEx != null) {
throw firstAttemptEx;
}
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
StringBuilder msg = new StringBuilder();
msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
msg.append("] to required type [").append(ClassUtils.getQualifiedName(requiredType)).append("]");
if (propertyName != null) {
msg.append(" for property '").append(propertyName).append("'");
}
if (editor != null) {
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
"] returned inappropriate value of type [").append(
ClassUtils.getDescriptiveType(convertedValue)).append("]");
throw new IllegalArgumentException(msg.toString());
}
else {
msg.append(": no matching editors or conversion strategy found");
throw new IllegalStateException(msg.toString());
}
}
} if (firstAttemptEx != null) {
if (editor == null && !standardConversion && requiredType != null && !Object.class.equals(requiredType)) {
throw firstAttemptEx;
}
logger.debug("Original ConversionService attempt failed - ignored since " +
"PropertyEditor based conversion eventually succeeded", firstAttemptEx);
} return (T) convertedValue;
}

类org.springframework.beans.BeanUtils
方法PropertyEditor findEditorByConvention(Class<?> targetType)

spring会自动获取type对应的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.put(targetType, Boolean.TRUE);
return null;
}
return (PropertyEditor) instantiateClass(editorClass);
}

例如对org.springframework.data.redis.core.ListOperations则有org.springframework.data.redis.core.ListOperationsEditor

class ListOperationsEditor extends PropertyEditorSupport {

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

Spring源码追踪1——doGetBean(为什么org.springframework.data.redis.core.RedisTemplate的实例可以注入为ListOperations)的更多相关文章

  1. Spring源码追踪2——xml解析入口

    解析xml节点入口 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDe ...

  2. Spring源码追踪3——AOP机制

    研究代码: spring配置文件 <cache:annotation-driven /> Java代码 @Cacheable(value = "test", key = ...

  3. Spring源码追踪4——SpringMVC View解析

    这次的议题是返回json和返回普通view经过的路线差异. ---------------------------------------------------------------------- ...

  4. spring源码开发环境搭建

    下载spring源码 地址 https://github.com/spring-projects/spring-framework 可以下载release版本,也可以直接git clone当前开发版本 ...

  5. Spring 源码学习之环境搭建

    一.下载Spring 源码 进入 https://github.com/spring-projects/spring-framework/tags 选择下载spring freamework的版本 h ...

  6. Spring Boot 注解之ObjectProvider源码追踪

    最近依旧在学习阅读Spring Boot的源代码,在此过程中涉及到很多在日常项目中比较少见的功能特性,对此深入研究一下,也挺有意思,这也是阅读源码的魅力之一.这里写成文章,分享给大家. 自动配置中的O ...

  7. Spring源码解读Spring IOC原理

    一.什么是Ioc/DI? IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等. 先从我们自己设计这样一个视角来考虑: 所谓控制反转,就是把原先我们代码里面需要实现的对象创建.依赖的代码,反 ...

  8. Spring源码分析——BeanFactory体系之抽象类、类分析(二)

    上一篇分析了BeanFactory体系的2个类,SimpleAliasRegistry和DefaultSingletonBeanRegistry——Spring源码分析——BeanFactory体系之 ...

  9. spring源码分析(一)IoC、DI

    创建日期:2016.08.06 修改日期:2016.08.07 - 2016.08.12 交流QQ:992591601 参考书籍:<spring源码深度解析>.<spring技术内幕 ...

随机推荐

  1. java注解小随笔

    注解分类 编码期间:SOURCE 编译期间:CLASS 运行期间:RUNTIME 自定义注解 //CLASS/RUNTIME/SOURCE 生效时机 @Retention(RetentionPolic ...

  2. https与http的区别

    HTTPS协议 由于http协议中,服务器和客户端之间传输的报文是明文,很容易被攻击截取,为了保证一些敏感信息的安全,https协议在http的基础上加了一层SSL协议,依靠证书来保证服务器和客户端之 ...

  3. django admin的实用配置

    https://www.cnblogs.com/wumingxiaoyao/p/6928297.html

  4. oracle异机恢复参考官方文档

    How to use Rman Duplicate on ASM/RAC/OMF/Single Instance (Doc ID 840647.1) How to perform Rman dupli ...

  5. Luogu3579 Solar Panels

    整除分块枚举... 真的没有想到会这么简单. 要使一个数 \(p\) 满足 条件, 则 存在\(x, y\), \(a<=x \times p<=b\ \&\&\ c< ...

  6. python 12 模块与包

    一.不知道什么原则 python文件下面只写方法,所有的可直接执行的代码,都放在条件下 原因.该文件有可能被其他文件调用 二.eval() 将字符串转为相应的数据格式可以想象json转为map 三.模 ...

  7. filebeat 收集的进度日志查看

    filebeat 收集的日志进度和文件在data 目录中是有保存的 默认路径地址: /usr/share/filebeat/data 里面有两个文件: meta.json:{"uuid&qu ...

  8. 安卓学习第一节--环境搭建及Android Studio 安装

    1.安装JDK 2.安装AS 安装参考网址 https://www.cnblogs.com/xiadewang/p/7820377.html 下载网址: http://www.android-stud ...

  9. Python之PIL库

    Python PIL PIL (Python Image Library) 库是Python 语言的一个第三方库,PIL库支持图像存储.显示和处理,能够处理几乎所有格式的图片. 一.PIL库简介 1. ...

  10. java之路 把1到100之间的数的偶数相加

    /** *把1到100之间的数的偶数相加 */ class Demo{ public static void main(String[] args){ int i =1; int sum = 0; d ...