spring–BeanWrapper
文章目录
- spring--`BeanWrapper`
- 1 用途
- 2 `BeanWrapperImpl`的继承体系
- 3 `spring`实例化`bean`后创建`BeanWrapper`对象
- 4 `AbstractNestablePropertyAccessor`
- 5 `PropertyDescriptor`
- 6 `BeanWrapperImpl`
- 7 `isWritableProperty(String propertyName)`方法,判断属性是否可写
- 8 `getPropertyHandler(String propertyName)`方法,获取指定属性名的`PropertyHandler`
- 9 `setPropertyValues(PropertyValues pvs)`方法,填充经过初步处理的属性(可能还没有进行类型转换)
- 10 `spring`使用内省
1 用途
它最大的作用就是将
bean
实例和类型转换对象封装到一起,对属性进行类型转换
2 BeanWrapperImpl
的继承体系
典型的接口隔离,一层一层的增加功能。
总结:
PropertyEditorRegistry
接口很简单,提供注册和查找自定义的PropertyEditor
功能,这个接口很重要,如果我们需要向spring
中注册自定义的PropertyEditor
,就需要借助这个接口。TypeConverter
接口定义的4个方法,都是判断是否需要进行类型转换,后面三个方法标识object
的来源(方法参数,属性)。PropertyAccessor
属性寄存器,提供了访问属性PropertyValue
的方法,以及判断属性是否可读可写。ConfigurablePropertyAccessor
可配的属性寄存器,接口提供了几个设置ConversionService
的方法。BeanWrapper
接口就简单了,获取实例,获取实例类型,获取bean
的属性描述。BeanWrapper
拥有上述所有接口的功能。但是spring
为什么要提供这样一个bean
的包装呢?其实主要是为了解决两个问题
bean
实例化之后,需要进行属性填充,此时就需要就行属性访问和设置了。XML
中配置bean
的属性值均为String
类型,而该属性的真实类型却不一定是String
,此时需要进行类型转换。
3 spring
实例化bean
后创建BeanWrapper
对象
经过前面几篇文章的学习,我们知道spring
在实例化bean
之后,就会将bean
包装为Beanwrapper
类型的对象
下面是spring
实例化bean
的过程
/**
* Instantiate the given bean using its default constructor.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return a BeanWrapper for the new instance
*/
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(
(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
getAccessControlContext());
}
else {
//策略模式完成bean的实例化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}
//使用实例化后的对象构建一个BeanWrapper,见3.1
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
//初始化BeanWrapper,见3.2
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
3.1 使用实例化后的对象构建一个BeanWrapper
/**
* Create a new BeanWrapperImpl for the given object.
* @param object the object wrapped by this BeanWrapper
*/
public BeanWrapperImpl(Object object) {
super(object);
}
调用父类构造方法完成对象创建
/**
* Create a new accessor for the given object.
* @param object the object wrapped by this accessor
*/
protected AbstractNestablePropertyAccessor(Object object) {
//允许向BeanWrapper中注册默认的PropertyEditor
registerDefaultEditors();
//保存被包装的实例
setWrappedInstance(object);
}
/**
* Activate the default editors for this registry instance,
* allowing for lazily registering default editors when needed.
* 开启懒加载的方式向BeanWrapper中注册默认的PropertyEditor,用于兜底,
* 当找不到合适的PropertyEditor用于类型转换,就尝试使用默认的
*/
protected void registerDefaultEditors() {
this.defaultEditorsActive = true;
}
/**
* Switch the target object, replacing the cached introspection results only
* if the class of the new object is different to that of the replaced object.
* @param object the new target object
* 保存被包装的实例
*/
public void setWrappedInstance(Object object) {
//这个方法被子类BeanWrapperImpl重写了
setWrappedInstance(object, "", null);
}
/**
* Switch the target object, replacing the cached introspection results only
* if the class of the new object is different to that of the replaced object.
* @param object the new target object
* @param nestedPath the nested path of the object
* @param rootObject the root object at the top of the path
* 这个方法又被子类调用了
*/
public void setWrappedInstance(Object object, @Nullable String nestedPath, @Nullable Object rootObject) {
//保存当前被包装的实例
this.wrappedObject = ObjectUtils.unwrapOptional(object);
Assert.notNull(this.wrappedObject, "Target object must not be null");
this.nestedPath = (nestedPath != null ? nestedPath : "");
/**
* 这个rootObject是什么,已经有了wrappedObject为什么还需要一个rootObject?
* 其实这个rootObject主要用来保存嵌套属性的上级实例
* 举个例子, 对于这种情况<property name="role.rolename" value="wx"></property>
* 我们只获取到user对象的BeanWrapper肯定不行,因为你根本不可能使用反射跨类调用setRolename
* 方法来将值设置到user对象中,必须要获得role的BeanWrapper,然后使用反射修改值。
* 在这种情况下,wrappedObject是role对象,而rootObject就是user对象了
*/
this.rootObject = (!this.nestedPath.isEmpty() ? rootObject : this.wrappedObject);
this.nestedPropertyAccessors = null;
//委托模式,将具体的类型转换逻辑委托给了TypeConverterDelegate
this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject);
}
BeanWrapperImpl
重写setWrappedInstance
方法
@Override
public void setWrappedInstance(Object object, @Nullable String nestedPath, @Nullable Object rootObject) {
//又调用了父类的setWrappedInstance方法
super.setWrappedInstance(object, nestedPath, rootObject);
//重置内省的缓存
setIntrospectionClass(getWrappedClass());
}
//getClass方法获取实例的clazz对象
public final Class<?> getWrappedClass() {
return getWrappedInstance().getClass();
}
/**
* Set the class to introspect.
* Needs to be called when the target object changes.
* @param clazz the class to introspect
*/
protected void setIntrospectionClass(Class<?> clazz) {
//重置内省的缓存
if (this.cachedIntrospectionResults != null && this.cachedIntrospectionResults.getBeanClass() != clazz) {
this.cachedIntrospectionResults = null;
}
}
3.2 初始化BeanWrapper
/**
* Initialize the given BeanWrapper with the custom editors registered
* with this factory. To be called for BeanWrappers that will create
* and populate bean instances.
* <p>The default implementation delegates to {@link #registerCustomEditors}.
* Can be overridden in subclasses.
* @param bw the BeanWrapper to initialize
*/
protected void initBeanWrapper(BeanWrapper bw) {
/**
* getConversionService()方法获取工厂中的ConversionServic对象
* 将其注册到BeanWrapper中
*/
bw.setConversionService(getConversionService());
//将用户自定义的PropertyEditor注册到BeanWrapper中
registerCustomEditors(bw);
}
将用户自定义的PropertyEditor
注册到BeanWrapper
中
/**
* Initialize the given PropertyEditorRegistry with the custom editors
* that have been registered with this BeanFactory.
* <p>To be called for BeanWrappers that will create and populate bean
* instances, and for SimpleTypeConverter used for constructor argument
* and factory method type conversion.
* @param registry the PropertyEditorRegistry to initialize
*/
protected void registerCustomEditors(PropertyEditorRegistry registry) {
PropertyEditorRegistrySupport registrySupport =
(registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null);
if (registrySupport != null) {
registrySupport.useConfigValueEditors();
}
//执行工厂中的所有PropertyEditorRegistrar的registerCustomEditors方法批量注册用户自定义的PropertyEditor
if (!this.propertyEditorRegistrars.isEmpty()) {
for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) {
try {
registrar.registerCustomEditors(registry);
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) {
if (logger.isDebugEnabled()) {
logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() +
"] failed because it tried to obtain currently created bean '" +
ex.getBeanName() + "': " + ex.getMessage());
}
onSuppressedException(ex);
continue;
}
}
throw ex;
}
}
}
//实例化并注册用户自定义的PropertyEditor
if (!this.customEditors.isEmpty()) {
this.customEditors.forEach((requiredType, editorClass) ->
registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass)));
}
}
结合我们在配置文件中配置的CustomEditorConfigurer
,它是一个BeanFactoryPostProcessor
,所以我们直接看postProcessBeanFactory
方法
@Nullable
private PropertyEditorRegistrar[] propertyEditorRegistrars;
@Nullable
private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertyEditorRegistrars != null) {
for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
//注册到工厂中
beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);
}
}
if (this.customEditors != null) {
//注册到工厂中
this.customEditors.forEach(beanFactory::registerCustomEditor);
}
}
也就是说,只要我们将自定义的PropertyEditorRegistrar
或者PropertyEditor
放到CustomEditorConfigurer
中,spring
就会自动的使用它们。
4 AbstractNestablePropertyAccessor
该类是
BeanWrapperImpl
的父类,之所以在这里开一个章节讲解它的父类,主要是因为下面的方法大量用到这个类,不讲解清楚就看不懂流程。
首先来看它的属性
public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyAccessor {
private int autoGrowCollectionLimit = Integer.MAX_VALUE;
//被包装的bean对象
@Nullable
Object wrappedObject;
//嵌套路径
private String nestedPath = "";
//根对象
@Nullable
Object rootObject;
/**
* 缓存的嵌套属性寄存器实例
* nested path -> Accessor instance
*/
@Nullable
private Map<String, AbstractNestablePropertyAccessor> nestedPropertyAccessors;
}
4.1 PropertyHandler
该类是
AbstractNestablePropertyAccessor
的抽象嵌套类
/**
* A handler for a specific property.
*/
protected abstract static class PropertyHandler {
//属性类型
private final Class<?> propertyType;
//是否可读
private final boolean readable;
//是否可写
private final boolean writable;
public PropertyHandler(Class<?> propertyType, boolean readable, boolean writable) {
this.propertyType = propertyType;
this.readable = readable;
this.writable = writable;
}
public Class<?> getPropertyType() {
return this.propertyType;
}
public boolean isReadable() {
return this.readable;
}
public boolean isWritable() {
return this.writable;
}
public abstract TypeDescriptor toTypeDescriptor();
public abstract ResolvableType getResolvableType();
@Nullable
public Class<?> getMapKeyType(int nestingLevel) {
return getResolvableType().getNested(nestingLevel).asMap().resolveGeneric(0);
}
@Nullable
public Class<?> getMapValueType(int nestingLevel) {
return getResolvableType().getNested(nestingLevel).asMap().resolveGeneric(1);
}
@Nullable
public Class<?> getCollectionType(int nestingLevel) {
return getResolvableType().getNested(nestingLevel).asCollection().resolveGeneric();
}
@Nullable
public abstract TypeDescriptor nested(int level);
@Nullable
public abstract Object getValue() throws Exception;
public abstract void setValue(@Nullable Object value) throws Exception;
}
而它对应的实现定义在
BeanWrapperImpl
类中,不过此时它是一个内部类
private class BeanPropertyHandler extends PropertyHandler {
//属性描述
private final PropertyDescriptor pd;
//PropertyDescriptor中保存了属性所有信息,快速初始化一个属性处理器
public BeanPropertyHandler(PropertyDescriptor pd) {
super(pd.getPropertyType(), pd.getReadMethod() != null, pd.getWriteMethod() != null);
this.pd = pd;
}
@Override
public ResolvableType getResolvableType() {
//解析getter方法的返回值
return ResolvableType.forMethodReturnType(this.pd.getReadMethod());
}
/**
* 获取当前属性的类型描述
* 具体的过程见10.3和10.4
*/
@Override
public TypeDescriptor toTypeDescriptor() {
return new TypeDescriptor(property(this.pd));
}
//嵌套属性的类型描述
@Override
@Nullable
public TypeDescriptor nested(int level) {
return TypeDescriptor.nested(property(this.pd), level);
}
/**
* 获取属性值
* 实际上就是通过反射调用getter方法得到属性值
*/
@Override
@Nullable
public Object getValue() throws Exception {
Method readMethod = this.pd.getReadMethod();
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(readMethod);
return null;
});
try {
return AccessController.doPrivileged((PrivilegedExceptionAction<Object>)
() -> readMethod.invoke(getWrappedInstance(), (Object[]) null), acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
ReflectionUtils.makeAccessible(readMethod);
return readMethod.invoke(getWrappedInstance(), (Object[]) null);
}
}
/**
* 设置属性值
* 实际上就是通过反射调用setter方法设置属性值
*/
@Override
public void setValue(@Nullable Object value) throws Exception {
Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
this.pd.getWriteMethod());
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(writeMethod);
return null;
});
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>)
() -> writeMethod.invoke(getWrappedInstance(), value), acc);
}
catch (PrivilegedActionException ex) {
throw ex.getException();
}
}
else {
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(getWrappedInstance(), value);
}
}
}
总结:该类封装了属性的所有信息,提供一些字段缓存了我们需要经常访问的计算结果,并提供
setValue()
方法、getValue()
方法设置和获取属性
4.2 PropertyTokenHolder
该类是
AbstractNestablePropertyAccessor
的嵌套类
/**
* Holder class used to store property tokens.
*/
protected static class PropertyTokenHolder {
public PropertyTokenHolder(String name) {
this.actualName = name;
this.canonicalName = name;
}
//属性的真实名字
public String actualName;
//规范名称名
public String canonicalName;
//[]中的内容
@Nullable
public String[] keys;
}
简单封装属性名
5 PropertyDescriptor
属性描述
6 BeanWrapperImpl
public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper {
/**
* 内省工具类,提供了很多支持内省的方法
* 并缓存内省结果
*/
@Nullable
private CachedIntrospectionResults cachedIntrospectionResults;
/**
* 安全上下文
*/
@Nullable
private AccessControlContext acc;
}
BeanWrapperImpl
类还是比较简单的,它仅仅在父类的基础上提供内省支持
6.1 构造方法
/**
* Create a new BeanWrapperImpl for the given object,
* registering a nested path that the object is in.
* @param object the object wrapped by this BeanWrapper
* @param nestedPath the nested path of the object
* @param parent the containing BeanWrapper (must not be {@code null})
*/
private BeanWrapperImpl(Object object, String nestedPath, BeanWrapperImpl parent) {
super(object, nestedPath, parent);
setSecurityContext(parent.acc);
}
父类构造方法完成对象初始化
/**
* Create a new accessor for the given object,
* registering a nested path that the object is in.
* @param object the object wrapped by this accessor
* @param nestedPath the nested path of the object
* @param parent the containing accessor (must not be {@code null})
*/
protected AbstractNestablePropertyAccessor(Object object, String nestedPath, AbstractNestablePropertyAccessor parent) {
//该方法见3.1,核心是保存父对象parent.getWrappedInstance()
setWrappedInstance(object, nestedPath, parent.getWrappedInstance());
//下面都是一些字段值的的拷贝
setExtractOldValueForEditor(parent.isExtractOldValueForEditor());
setAutoGrowNestedPaths(parent.isAutoGrowNestedPaths());
setAutoGrowCollectionLimit(parent.getAutoGrowCollectionLimit());
setConversionService(parent.getConversionService());
}
这个构造方法你就关心一下
setWrappedInstance()
方法即可
7 isWritableProperty(String propertyName)
方法,判断属性是否可写
public boolean isWritableProperty(String propertyName) {
try {
//获取指定属性名的PropertyHandler属性处理器,见8
PropertyHandler ph = getPropertyHandler(propertyName);
//判断该属性是否可写(setter方法)
if (ph != null) {
return ph.isWritable();
}
else {
// Maybe an indexed/mapped property...
getPropertyValue(propertyName);
return true;
}
}
/**
* 此处的异常捕获很重要,当我们propertyName是嵌套属性名,且外层属性没有初始值的时候
* 获取propertyName对应的PropertyHandler属性处理器就会抛异常,由此处捕获,返回false
* 表明该嵌套属性不可写,然后该属性就不会现在进行类型转换,而是等到属性填充的时候(也就是第9章节
* 的方法)再进行类型转换
*/
catch (InvalidPropertyException ex) {
// Cannot be evaluated, so can't be writable.
}
return false;
}
8 getPropertyHandler(String propertyName)
方法,获取指定属性名的PropertyHandler
/**
* Return the {@link PropertyHandler} for the specified {@code propertyName}, navigating
* if necessary. Return {@code null} if not found rather than throwing an exception.
* @param propertyName the property to obtain the descriptor for
* @return the property descriptor for the specified property,
* or {@code null} if not found
* @throws BeansException in case of introspection failure
*/
@Nullable
protected PropertyHandler getPropertyHandler(String propertyName) throws BeansException {
Assert.notNull(propertyName, "Property name must not be null");
//递归检查并获取属性的PropertyAccessor对象,见8.1
AbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName);
/**
* getFinalPath()方法,获取最后一个属性名,例如role.rolename,那么调用该方法后就是rolename,见8.2
* getLocalPropertyHandler()方法,获取属性处理器,见8.3
*/
return nestedPa.getLocalPropertyHandler(getFinalPath(nestedPa, propertyName));
}
8.1 递归检查并获取属性的PropertyAccessor
对象
主要是考虑到这种情况
<bean id="user" class="com.lx.converter.domain.User">
<!--这两个不能调换顺序,否则会报错-->
<property name="role" ref="role"></property>
<!--可以覆盖role中的默认值-->
<property name="role.rolename" value="role"></property>
</bean>
<bean id="role" class="com.lx.converter.domain.Role">
<property name="rolename" value="lx"></property>
</bean>
对role.rolename
的进行特殊处理
/**
* Recursively navigate to return a property accessor for the nested property path.
* @param propertyPath property path, which may be nested
* @return a property accessor for the target bean
*/
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
//获取第一个属性分隔符的索引(分隔符为.)
int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
// Handle nested properties recursively.
//嵌套属性,进行递归
if (pos > -1) {
//外层的属性role
String nestedProperty = propertyPath.substring(0, pos);
//内层的rolename
String nestedPath = propertyPath.substring(pos + 1);
//获取role的属性寄存器
AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);
//递归,判断rolename中是否还有嵌套,获取到最终属性的PropertyAccessor
return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);
}
//非嵌套属性,直接使用当前bean属性寄存器,即当前BeanWrapperImpl对象
else {
return this;
}
}
我们来看一下role
属性的属性寄存器是如何获取的?
/**
* Retrieve a Property accessor for the given nested property.
* Create a new one if not found in the cache.
* <p>Note: Caching nested PropertyAccessors is necessary now,
* to keep registered custom editors for nested properties.
* @param nestedProperty property to create the PropertyAccessor for
* @return the PropertyAccessor instance, either cached or newly created
*/
private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
//缓存的嵌套属性寄存器,见4
if (this.nestedPropertyAccessors == null) {
this.nestedPropertyAccessors = new HashMap<>();
}
// Get value of bean property.
/**
* 这里解析属性名,获取规范名,见8.1.1
* 还是role,然后新旧名字封装成PropertyTokenHolder
*/
PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
//规范名
String canonicalName = tokens.canonicalName;
/**
* 获取bean对象中指定属性对应的值,见8.1.2
* 获取role属性对象,通过getter方法得到
* 初次访问value肯定是null,因为我们并没有给role属性设置值
*/
Object value = getPropertyValue(tokens);
/**
* role属性为null,但是你却想给role内部的rolename赋值,那肯定抛异常
*/
if (value == null || (value instanceof Optional && !((Optional<?>) value).isPresent())) {
if (isAutoGrowNestedPaths()) {
value = setDefaultValue(tokens);
}
//抛异常,跳过后面的代码
else {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + canonicalName);
}
}
/*****************************************************************************/
// Lookup cached sub-PropertyAccessor, create new one if not found.
/**
* 到了这一步就说明嵌套属性的外部属性有值,即对于role.rolename来说,role属性有值
* 值从哪儿来的,有两种情况
* 1.private Role role=new Role(),role有默认值(Field)
* 2.调用getRole()方法的返回不为null(Property)
* 3.role属性已经进行属性填充了,现在填充role.rolename了,所以此时能够获取到role对象(对应9
* 章节中调用该方法)
*
* 8章节对应的方法会在两个地方法被调用,第一个是7中的isWritableProperty()方法中调用一次,
* 此时若是嵌套属性,通过getter方法访问外部属性得到null,那么此时嵌套属性就不可写,不会马上进行
* 类型转换,而是等到9章节方法调用时再尝试一次
*/
//再次从缓存中获取一次嵌套属性的属性寄存器
AbstractNestablePropertyAccessor nestedPa = this.nestedPropertyAccessors.get(canonicalName);
if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) {
if (logger.isTraceEnabled()) {
logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'");
}
//将外部属性对象包装为BeanWrapperImpl对象
nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR);
// Inherit all type-specific PropertyEditors.
//拷贝PropertyEditor到刚创建的BeanWrapperImpl对象中
copyDefaultEditorsTo(nestedPa);
copyCustomEditorsTo(nestedPa, canonicalName);
//缓存嵌套属性的PropertyAccessor
this.nestedPropertyAccessors.put(canonicalName, nestedPa);
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Using cached nested property accessor for property '" + canonicalName + "'");
}
}
return nestedPa;
}
/**
* 创建外部属性对象的BeanWrapperImpl对象
* 保存了父BeanWrapperImpl对象,见6.1
*/
protected BeanWrapperImpl newNestedPropertyAccessor(Object object, String nestedPath) {
return new BeanWrapperImpl(object, nestedPath, this);
}
对于嵌套属性,
getNestedPropertyAccessor(String nestedProperty)
方法会进来2
次
- 第一次进来,是在
isWritableProperty(String propertyName)
方法中,它尝试获取外部属性值,发现外部属性默认值为null
,于是方法就抛出异常,被isWritableProperty(String propertyName)
方法捕获到异常,直接返回false
,表明当前属性不可写,跳过初次类型转换- 第二次进来,是在
setPropertyValues(PropertyValues pvs)
方法中,该方法中开始按照顺序对每一个属性进行填充,发现有属性(也就是嵌套属性)还没有进行类型转换,于是就先取出外部属性值,包装为BeanWrapperImpl
对象,然后进行类型转换,再通过这个BeanWrapperImpl
对象的getLocalPropertyHandler()
方法得到对应属性的属性处理器PropertyHandler
,最后调用属性处理器的setValue()
方法填充属性BeanWrapperImpl
就是属性寄存器
8.1.1 将属性名解析为相应的属性名称标记
/**
* Parse the given property name into the corresponding property name tokens.
* @param propertyName the property name to parse
* @return representation of the parsed property tokens
*/
private PropertyTokenHolder getPropertyNameTokens(String propertyName) {
String actualName = null;
List<String> keys = new ArrayList<>(2);
int searchIndex = 0;
while (searchIndex != -1) {
/**
* PROPERTY_KEY_PREFIX=[
* 从索引位置searchIndex开始获得propertyName中[的索引
*/
int keyStart = propertyName.indexOf(PROPERTY_KEY_PREFIX, searchIndex);
searchIndex = -1;
//属性名中有[
if (keyStart != -1) {
//找到与这个[对应的]索引位置
int keyEnd = getPropertyNameKeyEnd(propertyName, keyStart + PROPERTY_KEY_PREFIX.length());
//找到了
if (keyEnd != -1) {
/**
* 只有第一次才会给actualName赋值
* 也就是说,propertyName中第一个[符号左边的字符串就是该属性的真实名
*/
if (actualName == null) {
/**
* 真实的属性名
* 这里截取的是[之前的部分
*/
actualName = propertyName.substring(0, keyStart);
}
//得到[]符号中的内容
String key = propertyName.substring(keyStart + PROPERTY_KEY_PREFIX.length(), keyEnd);
/**
* []中的内容有3种写法
* 1.什么都不加
* 2.'内容'
* 3.\内容
*/
if (key.length() > 1 && (key.startsWith("'") && key.endsWith("'")) ||
(key.startsWith("\"") && key.endsWith("\""))) {
key = key.substring(1, key.length() - 1);
}
//保存到keys集合中
keys.add(key);
/**
* PROPERTY_KEY_SUFFIX=]
* 接着去解析下一个[]符号内容
* 主要是为了解决wx[xx].de[xx]
*/
searchIndex = keyEnd + PROPERTY_KEY_SUFFIX.length();
}
}
}
/**
* 使用真实属性名创建一个属性名称标记对象,见4.2
*/
PropertyTokenHolder tokens = new PropertyTokenHolder(actualName != null ? actualName : propertyName);
//属性名中有[]
if (!keys.isEmpty()) {
/**
* 属性名中有[]的属性的规范名称
* collectionToDelimitedString()方法,将keys集合转[]符号分割的字符串
*/
tokens.canonicalName += PROPERTY_KEY_PREFIX +
StringUtils.collectionToDelimitedString(keys, PROPERTY_KEY_SUFFIX + PROPERTY_KEY_PREFIX) +
PROPERTY_KEY_SUFFIX;
//集合转数组,并保存到规范名称标记对象中
tokens.keys = StringUtils.toStringArray(keys);
}
return tokens;
}
/**
* 找到与[匹配的]
* 可能存在[df[dg]]这种情况
*/
private int getPropertyNameKeyEnd(String propertyName, int startIndex) {
int unclosedPrefixes = 0;
int length = propertyName.length();
for (int i = startIndex; i < length; i++) {
switch (propertyName.charAt(i)) {
//[
case PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR:
// The property name contains opening prefix(es)...
unclosedPrefixes++;
break;
//]
case PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR:
if (unclosedPrefixes == 0) {
// No unclosed prefix(es) in the property name (left) ->
// this is the suffix we are looking for.
return i;
}
else {
// This suffix does not close the initial prefix but rather
// just one that occurred within the property name.
unclosedPrefixes--;
}
break;
}
}
return -1;
}
总结:
- 如果属性名中不包含
[]
符号,那么属性真实名actualName
直接就是原始名,不用处理- 如果属性名中包含
[]
符号,那么就需要做如下处理
- 首先获取原始属性名中第一个
[
符号左边的内容作为属性真实名actualName
- 随后一个一个的解析
[]
符号,得到里面的内容,保存到keys
集合中。这里只会解析并行的wx[xx].de[lx]
,不会解析[df[dg]]
,也就是说第一个能解析到xx
和lx
,第二个只能直接到df[dg]
,毕竟第二种写法不对。- 最后就开始拼接了,得到规范名称,按
tokens.canonicalName += PROPERTY_KEY_PREFIX +StringUtils.collectionToDelimitedString(keys, PROPERTY_KEY_SUFFIX + PROPERTY_KEY_PREFIX) +PROPERTY_KEY_SUFFIX;
规则
8.1.2 获取bean
对象中指定属性对应的值
protected Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
//规范名
String propertyName = tokens.canonicalName;
//真实名
String actualName = tokens.actualName;
/**
* 获取指定属性名的PropertyHandler属性处理器,见8.3
* 就是通过内省访问User,然后获取role属性的PropertyHandler
*/
PropertyHandler ph = getLocalPropertyHandler(actualName);
//isReadable()判断属性有没有对应的getter方法
if (ph == null || !ph.isReadable()) {
throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName);
}
try {
/**
* 反射调用属性的getter方法得到属性值,见4.1
* 实际上就是调用role属性的getter方法,获取role对象
* 获取到这个role对象就可以修改它的属性值了
*/
Object value = ph.getValue();
/*******************************处理keys********************************/
//这里面的keys我也没弄懂,先放一下
if (tokens.keys != null) {
if (value == null) {
if (isAutoGrowNestedPaths()) {
value = setDefaultValue(new PropertyTokenHolder(tokens.actualName));
}
else {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
"Cannot access indexed value of property referenced in indexed " +
"property path '" + propertyName + "': returned null");
}
}
StringBuilder indexedPropertyName = new StringBuilder(tokens.actualName);
// apply indexes and map keys
for (int i = 0; i < tokens.keys.length; i++) {
String key = tokens.keys[i];
if (value == null) {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
"Cannot access indexed value of property referenced in indexed " +
"property path '" + propertyName + "': returned null");
}
else if (value.getClass().isArray()) {
int index = Integer.parseInt(key);
value = growArrayIfNecessary(value, index, indexedPropertyName.toString());
value = Array.get(value, index);
}
else if (value instanceof List) {
int index = Integer.parseInt(key);
List<Object> list = (List<Object>) value;
growCollectionIfNecessary(list, index, indexedPropertyName.toString(), ph, i + 1);
value = list.get(index);
}
else if (value instanceof Set) {
// Apply index to Iterator in case of a Set.
Set<Object> set = (Set<Object>) value;
int index = Integer.parseInt(key);
if (index < 0 || index >= set.size()) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Cannot get element with index " + index + " from Set of size " +
set.size() + ", accessed using property path '" + propertyName + "'");
}
Iterator<Object> it = set.iterator();
for (int j = 0; it.hasNext(); j++) {
Object elem = it.next();
if (j == index) {
value = elem;
break;
}
}
}
else if (value instanceof Map) {
Map<Object, Object> map = (Map<Object, Object>) value;
Class<?> mapKeyType = ph.getResolvableType().getNested(i + 1).asMap().resolveGeneric(0);
// IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values.
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
value = map.get(convertedMapKey);
}
else {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Property referenced in indexed property path '" + propertyName +
"' is neither an array nor a List nor a Set nor a Map; returned value was [" + value + "]");
}
indexedPropertyName.append(PROPERTY_KEY_PREFIX).append(key).append(PROPERTY_KEY_SUFFIX);
}
}
/********************************************************************/
//直接返回getter方法的调用结果,即属性对应值
return value;
}
catch (IndexOutOfBoundsException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Index of out of bounds in property path '" + propertyName + "'", ex);
}
catch (NumberFormatException | TypeMismatchException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Invalid index in property path '" + propertyName + "'", ex);
}
catch (InvocationTargetException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Getter for property '" + actualName + "' threw exception", ex);
}
catch (Exception ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Illegal attempt to get property '" + actualName + "' threw exception", ex);
}
}
总结:
- 调用
getLocalPropertyHandler(actualName)
方法得到真实属性名actualName
的PropertyHandler
属性处理器- 判断属性有没有
getter
方法,没有抛异常- 调用属性处理器的
ph.getValue()
方法得到属性默认值
8.2 获取属性中最后一部分(针对嵌套属性)
/**
* Get the last component of the path. Also works if not nested.
* @param pa property accessor to work on
* @param nestedPath property path we know is nested
* @return last component of the path (the property on the target bean)
*/
protected String getFinalPath(AbstractNestablePropertyAccessor pa, String nestedPath) {
/**
* 属性寄存器是当前的BeanWrapperImpl对象
* 说明当前属性不是嵌套属性,见8.1
* 那就直接使用当前属性路径
*/
if (pa == this) {
return nestedPath;
}
//否则截取属性,得到属性最后一部分
return nestedPath.substring(PropertyAccessorUtils.getLastNestedPropertySeparatorIndex(nestedPath) + 1);
}
- 非嵌套属性不做处理
- 嵌套属性则截取得到最后一个
.
后面部分
8.3 获取指定属性名的PropertyHandler
属性处理器
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
//获取属性名对应的PropertyDescriptor,见10.2.3
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
//创建一个BeanPropertyHandler属性处理器,见4.1
return (pd != null ? new BeanPropertyHandler(pd) : null);
}
/**
* Obtain a lazily initialized CachedIntrospectionResults instance
* for the wrapped object.
*/
private CachedIntrospectionResults getCachedIntrospectionResults() {
if (this.cachedIntrospectionResults == null) {
//内省,获取javabean对象属性信息,见10.2.2
this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(getWrappedClass());
}
return this.cachedIntrospectionResults;
}
总结:
通过
spring
封装的内省工具类cachedIntrospectionResults
的静态方法forClass(beanClass)
,得到所有属性描述PropertyDescriptor
,然后获取指定属性的属性描述,封装为属性处理器BeanPropertyHandler
9 setPropertyValues(PropertyValues pvs)
方法,填充经过初步处理的属性(可能还没有进行类型转换)
public void setPropertyValues(PropertyValues pvs) throws BeansException {
//调用重载的方法进行属性填充
setPropertyValues(pvs, false, false);
}
@Override
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
throws BeansException {
List<PropertyAccessException> propertyAccessExceptions = null;
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = true;
}
try {
//遍历,顺序填充属性
for (PropertyValue pv : propertyValues) {
// setPropertyValue may throw any BeansException, which won't be caught
// here, if there is a critical failure such as no matching field.
// We can attempt to deal only with less serious exceptions.
try {
//调用重载的方法进行属性填充
setPropertyValue(pv);
}
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new ArrayList<>();
}
propertyAccessExceptions.add(ex);
}
}
}
finally {
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = false;
}
}
// If we encountered individual exceptions, throw the composite exception.
//异常处理
if (propertyAccessExceptions != null) {
PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
throw new PropertyBatchUpdateException(paeArray);
}
}
这里出现了三个重载的
setPropertyValue()
方法,一步一步的细化职责,下面这个setPropertyValue
方法是针对单个属性进行填充的
@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
/**
* 嵌套属性会进入8.1.1,解析得到了PropertyTokenHolder对象,但是它并没有缓存
* 从下面的流程我们也能知道,只有非嵌套属性才会缓存PropertyTokenHolder对象
* 并且缓存之后它就进行属性填充了
* 所以只有非嵌套属性填充过一次之后它的tokens才不为空
* 主要为了解决覆盖问题
* <property name="name" value="lx"></property>
* <property name="name" value="wx"></property>
* 此种情况就不用每次解析属性名了
*/
PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
//一般都为null,进入此分支
if (tokens == null) {
//获取属性名
String propertyName = pv.getName();
AbstractNestablePropertyAccessor nestedPa;
try {
/**
* 获取属性名对应的属性寄存器,方法详情见8
*
* 如果是嵌套属性,在此处就能获取到它外部属性的属性寄存器了
* 这个方法里面会调用外部属性的getter方法得到外部属性对象,再封装为BeanWrapperImpl对象
* 也就是属性寄存器,这就是为什么要求getRole()方法在role.rolename赋值前必须有值的原因
*/
nestedPa = getPropertyAccessorForPropertyPath(propertyName);
}
catch (NotReadablePropertyException ex) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
"Nested property in path '" + propertyName + "' does not exist", ex);
}
/**
* getFinalPath(nestedPa, propertyName) 获取属性名最后一部分,见8.2
* 比如role.rolename对应的属性名字就是rolename
* getPropertyNameTokens()实际上就是载对rolename做进一步解析,里面可能有[]之类的符号
* 新旧名字封装形成PropertyTokenHolder,见8.1.1
*/
tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
//非嵌套属性缓存属性名称标记
if (nestedPa == this) {
/**
* 缓存属性名称标记
* pv.getOriginalPropertyValue()获取用来原始的PropertyValue对象
* 当我们要填充的属性是一个嵌套属性,且第一次判断它不可写的时候(即7章节),就跳过了类型转换
* 重新构建了一个PropertyValue对象,并将经过BeanDefinitionValueResolver解析的
* 属性值设为value字段值,然后调用setSource()方法保存保存原始的PropertyValue对象
* 如果不存在就返回this,也就是当前的PropertyValue
*/
pv.getOriginalPropertyValue().resolvedTokens = tokens;
}
//填充属性
nestedPa.setPropertyValue(tokens, pv);
}
//只有非嵌套属性且二次填充时才会进入该分支
else {
//填充属性
setPropertyValue(tokens, pv);
}
}
总结:
- 一般流程:首先得到它的属性寄存器,然后解析属性名称标记并缓存,最后调用
setPropertyValue(tokens, pv)
方法完成属性填充- 特殊情况:非嵌套属性且二次填充时,直接调用
setPropertyValue(tokens, pv)
方法完成属性填充最终发现,无论是嵌套属性还是非嵌套属性,最终都是调用
setPropertyValue(tokens, pv)
方法实现属性填充
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
//处理有[]的属性
if (tokens.keys != null) {
processKeyedProperty(tokens, pv);
}
//处理无[]的属性
else {
processLocalProperty(tokens, pv);
}
}
这里面的处理又是两个分支,分别对应这有
[]
符号的属性名和无[]
符号的属性名,这里只看第二种
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
//获取属性名对应的PropertyHandler,见8
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
//当前属性没有setter方法,那肯定不能进行属性填充了,抛异常
if (ph == null || !ph.isWritable()) {
if (pv.isOptional()) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring optional value for property '" + tokens.actualName +
"' - property not found on bean class [" + getRootClass().getName() + "]");
}
return;
}
if (this.suppressNotWritablePropertyException) {
// Optimization for common ignoreUnknown=true scenario since the
// exception would be caught and swallowed higher up anyway...
return;
}
throw createNotWritablePropertyException(tokens.canonicalName);
}
Object oldValue = null;
try {
//获取原始值
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
//需要进行类型转换,pv.conversionNecessary默认为null
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
//已经类型转换了
if (pv.isConverted()) {
//直接获取类型转换后的值
valueToApply = pv.getConvertedValue();
}
/**
* 没有类型转换
* 走到这一步一般是嵌套属性(role.rolename),在嵌套属性的上级对象(role)没有赋值之前
* ,你获取不到role对象的BeanWrapperImpl对象,也就不能进行类型转换了。
*/
else {
/**
* isExtractOldValueForEditor()判断是否需要提取旧值进行类型转换
* 就是判断extractOldValueForEditor字段值,默认为false
* ph.isReadable()判断属性有没有getter方法
*/
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
//调用属性的getter方法获取属性默认值
oldValue = ph.getValue();
}
catch (Exception ex) {
if (ex instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException) ex).getException();
}
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" +
this.nestedPath + tokens.canonicalName + "'", ex);
}
}
}
/**
*
* ph.toTypeDescriptor() 得到当前属性的类型描述,见4.1
* convertForProperty()方法,类型转换的核心方法,上篇文章讲过这个方法的源码
*/
valueToApply = convertForProperty(
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
}
//设置是否需要进行需要类型转换的标记,方便下次快速创建对象
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
//反射调用setter方法填充属性,见4.1
ph.setValue(valueToApply);
}
catch (TypeMismatchException ex) {
throw ex;
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
}
else {
Throwable cause = ex.getTargetException();
if (cause instanceof UndeclaredThrowableException) {
// May happen e.g. with Groovy-generated methods
cause = cause.getCause();
}
throw new MethodInvocationException(propertyChangeEvent, cause);
}
}
catch (Exception ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(
getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
}
总结一下该方法的大致流程:
- 遍历
MutablePropertyValues
,按顺序填充每一个PropertyValue
属性- 解析填充属性的属性名,得到
PropertyTokenHolder
属性名称标记(里面有真实属性名和规范属性名)- 调用
getLocalPropertyHandler(tokens.actualName)
方法得到属性的属性处理器PropertyHandler
- 验证属性是否包含
setter
方法,没有就抛异常- 判断
PropertyValue
属性是否有必要进行类型转换,没有必要就直接通过PropertyHandler
属性处理器ph.setValue(valueToApply)
方法完成属性赋值,否则就进入6
- 判断
PropertyValue
属性是否已经经过类型转换,未经过类型转换就先类型转换,然后填充属性值,否则直接填充属性值
10 spring
使用内省
内省是
java
提供的一种快捷访问javaBean
这种类型类的方式,本质上还是反射。通过内省,可以快速获得getter,setter
方法和它们对应的属性。通过内省获取某个类的属性必然包含class
属性,因为任何类的对象都有getClass
方法。
10.1 Field
和Property
的区别
Property
是相对于getter
、setter
方法来说的,一个getter
或setter
方法就代表了一个Property
。例如:我们可以通过user.getClass()
方法得到user
对象的clazz
对象,那么User
类和它的父类中真的定义了Class class=User.class
吗?肯定没有啊,但是我们却可以通过getClass()
方法得到clazz
对象,也就是说并没有为User
类分配了栈内存存储clazz
对象的引用。Field
则是JDK
反射定义的,用来代表类中分配了栈内存的字段,即明确在类中声明了Role role;
,这种就是Field
10.2 CachedIntrospectionResults
spring
封装了自己的内省工具类CachedIntrospectionResults
,也代表一个内省结果
10.2.1 CachedIntrospectionResults
的属性
public final class CachedIntrospectionResults {
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
//空的属性描述数组,如果某个类没有getter、setter方法,就会使用它
private static final PropertyDescriptor[] EMPTY_PROPERTY_DESCRIPTOR_ARRAY = {};
//得到根路径下spring.properties文件中spring.beaninfo.ignore的值
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
/**
* 通过某种算法逻辑得到所有的BeanInfoFactory对象
*/
private static final List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
//可使用的类加载器
static final Set<ClassLoader> acceptedClassLoaders =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
//内省结果缓存
static final ConcurrentMap<Class<?>, CachedIntrospectionResults> strongClassCache =
new ConcurrentHashMap<>(64);
//包含类内省结果缓存
static final ConcurrentMap<Class<?>, CachedIntrospectionResults> softClassCache =
new ConcurrentReferenceHashMap<>(64);
//内省结果得到的bean信息
private final BeanInfo beanInfo;
/**
* 某个类的所有属性描述
* 内省就是为了得到它
*/
private final Map<String, PropertyDescriptor> propertyDescriptors;
//属性描述对应的类型描述
private final ConcurrentMap<PropertyDescriptor, TypeDescriptor> typeDescriptorCache;
}
10.2.2 forClass(Class<?> beanClass)
方法, 得到beanClass
类的内省结果
/**
* Create CachedIntrospectionResults for the given bean class.
* @param beanClass the bean class to analyze
* @return the corresponding CachedIntrospectionResults
* @throws BeansException in case of introspection failure
*/
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
//先从缓存中获取
CachedIntrospectionResults results = strongClassCache.get(beanClass);
if (results != null) {
return results;
}
results = softClassCache.get(beanClass);
if (results != null) {
return results;
}
//创建一个beanClass的可缓存的内省结果
results = new CachedIntrospectionResults(beanClass);
ConcurrentMap<Class<?>, CachedIntrospectionResults> classCacheToUse;
//使用当前类加载器加载的是缓存安全的
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
isClassLoaderAccepted(beanClass.getClassLoader())) {
classCacheToUse = strongClassCache;
}
//不安全
else {
if (logger.isDebugEnabled()) {
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
}
classCacheToUse = softClassCache;
}
//缓存
CachedIntrospectionResults existing = classCacheToUse.putIfAbsent(beanClass, results);
return (existing != null ? existing : results);
}
/*****************************************************************************/
/**
* Create a new CachedIntrospectionResults instance for the given class.
* @param beanClass the bean class to analyze
* @throws BeansException in case of introspection failure
*/
private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
try {
if (logger.isTraceEnabled()) {
logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
}
//内省获取BeanInfo
this.beanInfo = getBeanInfo(beanClass);
if (logger.isTraceEnabled()) {
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
}
this.propertyDescriptors = new LinkedHashMap<>();
// This call is slow so we do it once.
//获取beanClass中所有PropertyDescriptor(原生或spring增强的)
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if (Class.class == beanClass &&
("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
// Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
continue;
}
if (logger.isTraceEnabled()) {
logger.trace("Found bean property '" + pd.getName() + "'" +
(pd.getPropertyType() != null ? " of type [" + pd.getPropertyType().getName() + "]" : "") +
(pd.getPropertyEditorClass() != null ?
"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
}
/**
* 增强PropertyDescriptor
* GenericTypeAwarePropertyDescriptor是spring定义,继承了PropertyDescriptor
* 添加了更多的方法,方便获取属性相关的信息
*/
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
//缓存起来
this.propertyDescriptors.put(pd.getName(), pd);
}
// Explicitly check implemented interfaces for setter/getter methods as well,
// in particular for Java 8 default methods...
Class<?> currClass = beanClass;
while (currClass != null && currClass != Object.class) {
//内省处理接口有默认实现的setter/getter方法
introspectInterfaces(beanClass, currClass);
currClass = currClass.getSuperclass();
}
this.typeDescriptorCache = new ConcurrentReferenceHashMap<>();
}
catch (IntrospectionException ex) {
throw new FatalBeanException("Failed to obtain BeanInfo for class [" + beanClass.getName() + "]", ex);
}
}
/**
* Retrieve a {@link BeanInfo} descriptor for the given target class.
* @param beanClass the target class to introspect
* @return the resulting {@code BeanInfo} descriptor (never {@code null})
* @throws IntrospectionException from the underlying {@link Introspector}
*/
private static BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
/**
* spring对原生的内省包装了一下
* 返回的BeanInfo类型是spring自己定义的ExtendedBeanInfo,实现更强大的功能,获取更多的信息
*/
for (BeanInfoFactory beanInfoFactory : beanInfoFactories) {
BeanInfo beanInfo = beanInfoFactory.getBeanInfo(beanClass);
if (beanInfo != null) {
return beanInfo;
}
}
//原生,使用的JDK中的Introspector工具类实现内省,返回SimpleBeanInfo,里面方法很少
return (shouldIntrospectorIgnoreBeaninfoClasses ?
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
Introspector.getBeanInfo(beanClass));
}
//内省处理接口有默认实现的setter/getter方法
private void introspectInterfaces(Class<?> beanClass, Class<?> currClass) throws IntrospectionException {
//遍历当前类的所有接口
for (Class<?> ifc : currClass.getInterfaces()) {
/**
* isJavaLanguageInterface方法判断是否是这几个Serializable、Externalizable、
* Closeable、AutoCloseable、Cloneable、Comparable接口
*/
if (!ClassUtils.isJavaLanguageInterface(ifc)) {
//内省获取接口的PropertyDescriptor
for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) {
/**
* 从子类的PropertyDescriptor集合中查找
* 判断子类是否重写了接口有默认实现的方法
*/
PropertyDescriptor existingPd = this.propertyDescriptors.get(pd.getName());
if (existingPd == null ||
(existingPd.getReadMethod() == null && pd.getReadMethod() != null)) {
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
// against a declared read method, so we prefer read method descriptors here.
//增强PropertyDescriptor
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
//缓存起来
this.propertyDescriptors.put(pd.getName(), pd);
}
}
//递归
introspectInterfaces(ifc, ifc);
}
}
}
真正的内省逻辑是在构造方法实现的,但是查看源码,我们发现构造方法是
private
,也就是说用户不能直接使用new CachedIntrospectionResults(beanClass)
的方式得到一个内省结果,而应该使用它提供的forClass(beanClass)
方法来得到内省结果。
10.2.3 getPropertyDescriptors()
方法,获取对应属性名的属性描述
@Nullable
PropertyDescriptor getPropertyDescriptor(String name) {
//通过名字得到对应的属性描述
PropertyDescriptor pd = this.propertyDescriptors.get(name);
if (pd == null && StringUtils.hasLength(name)) {
// Same lenient fallback checking as in Property...
pd = this.propertyDescriptors.get(StringUtils.uncapitalize(name));
if (pd == null) {
pd = this.propertyDescriptors.get(StringUtils.capitalize(name));
}
}
return pd;
}
每一个
CachedIntrospectionResults
对象中都缓存着内省得到的所有属性描述
10.2.4 getTypeDescriptor(PropertyDescriptor pd)
方法,获取对应属性的类型描述
@Nullable
TypeDescriptor getTypeDescriptor(PropertyDescriptor pd) {
return this.typeDescriptorCache.get(pd);
}
内省解析
beanClass
的时候只会得到所有属性对应的PropertyDescriptor
,如果需要TypeDescriptor
,首次需要用户自己解析创建TypeDescriptor
,然后加入到缓存typeDescriptorCache
中,后面使用就可以直接从缓存中拿了
10.2.5 addTypeDescriptor(PropertyDescriptor pd, TypeDescriptor td)
方法,缓存对应属性的类型描述
TypeDescriptor addTypeDescriptor(PropertyDescriptor pd, TypeDescriptor td) {
TypeDescriptor existing = this.typeDescriptorCache.putIfAbsent(pd, td);
return (existing != null ? existing : td);
}
用户解析创建
TypeDescriptor
类型描述之后,调用该方法将TypeDescriptor
加入到缓存typeDescriptorCache
中
10.3 Property
Property
:spring
定义的,用来描述一个javaBean
属性
这个property()
方法构造了一个Property
对象
private Property property(PropertyDescriptor pd) {
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
//构造一个Property对象
return new Property(gpd.getBeanClass(), gpd.getReadMethod(), gpd.getWriteMethod(), gpd.getName());
}
随后
spring
通过Property
对象构建一个TypeDescriptor
,要进行类型转换必须要得到TypeDescriptor
下面是Property
的字段
public final class Property {
private static Map<Property, Annotation[]> annotationCache = new ConcurrentReferenceHashMap<>();
//属性clazz对象
private final Class<?> objectType;
@Nullable
private final Method readMethod;
@Nullable
private final Method writeMethod;
//属性名
private final String name;
//方法参数
private final MethodParameter methodParameter;
//属性拥有的注解
@Nullable
private Annotation[] annotations;
}
10.3.1 构造方法
//使用的是这个构造方法创建的Property对象
public Property(
Class<?> objectType, @Nullable Method readMethod, @Nullable Method writeMethod, @Nullable String name) {
this.objectType = objectType;
this.readMethod = readMethod;
this.writeMethod = writeMethod;
//解析getter和setter方法参数,见10.3.2
this.methodParameter = resolveMethodParameter();
//根据方法名解析属性名,见10.3.3
this.name = (name != null ? name : resolveName());
}
构造
Property
的时候会解析出属性的名字和对应getter
、setter
方法参数
10.3.2 resolveMethodParameter()
方法,解析属性getter
和setter
方法参数
/**
* 解析getter和setter方法参数
* 从这个方法内容上看,优先使用setter方法的参数
* 当setter方法的参数为null或setter方法和getter方法的参数类型有继承关系的时候才用
* getter方法的参数
*/
private MethodParameter resolveMethodParameter() {
//获取读方法的方法参数对象
MethodParameter read = resolveReadMethodParameter();
//获取写方法的方法参数对象
MethodParameter write = resolveWriteMethodParameter();
if (write == null) {
if (read == null) {
//读写方法不能都没有参数
throw new IllegalStateException("Property is neither readable nor writeable");
}
//写方法没有参数就返回读方法的参数
return read;
}
if (read != null) {
Class<?> readType = read.getParameterType();
Class<?> writeType = write.getParameterType();
//读写方法参数不相同,并且具有继承关系则返回读方法参数
if (!writeType.equals(readType) && writeType.isAssignableFrom(readType)) {
return read;
}
}
return write;
}
/***************************************************************************************/
//读方法参数是返回值
@Nullable
private MethodParameter resolveReadMethodParameter() {
//实际上就是获取字段readMethod
if (getReadMethod() == null) {
return null;
}
return new MethodParameter(getReadMethod(), -1).withContainingClass(getObjectType());
}
//写方法参数是第一个参数
@Nullable
private MethodParameter resolveWriteMethodParameter() {
//实际上就是获取字段writeMethod
if (getWriteMethod() == null) {
return null;
}
//构建一个方法参数对象
return new MethodParameter(getWriteMethod(), 0).withContainingClass(getObjectType());
}
- 读方法参数实际上就是
getter
方法的返回值- 写方法参数实际上就是
setter
方法的第一个参数- 读方法和写方法不能都没有参数
- 当写方法没有参数的时候,就使用读方法参数,即
getter
方法的返回值- 如果读写方法参数都存在,那么只有写方法参数类型是读方法参数类型的父类时,才使用读方法参数,否则使用写方法参数
10.3.3 resolveName()
方法, 根据方法名解析出属性名
private String resolveName() {
if (this.readMethod != null) {
int index = this.readMethod.getName().indexOf("get");
if (index != -1) {
index += 3;
}
else {
index = this.readMethod.getName().indexOf("is");
if (index == -1) {
throw new IllegalArgumentException("Not a getter method");
}
index += 2;
}
return StringUtils.uncapitalize(this.readMethod.getName().substring(index));
}
else if (this.writeMethod != null) {
int index = this.writeMethod.getName().indexOf("set");
if (index == -1) {
throw new IllegalArgumentException("Not a setter method");
}
index += 3;
return StringUtils.uncapitalize(this.writeMethod.getName().substring(index));
}
else {
throw new IllegalStateException("Property is neither readable nor writeable");
}
}
/**
* The property type: e.g. {@code java.lang.String}
*/
public Class<?> getType() {
return this.methodParameter.getParameterType();
}
- 从这个方法内容上看,优先使用
getter
方法的名字作为name
的值getter
方法可以以get
或is
开头,去掉前缀,第一个字母小写就是name
的值setter
方法只能以set
开头,去掉前缀,第一个字母小写就是name
的值
10.4 TypeDescriptor
TypeDescriptor
是spring
定义的类型描述,它里面封装了最终要转换的类型,spring
根据这个对象进行类型转换
下面是TypeDescriptor
类的属性
public class TypeDescriptor implements Serializable {
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
//类型描述缓存
private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<>(32);
private static final Class<?>[] CACHED_COMMON_TYPES = {
boolean.class, Boolean.class, byte.class, Byte.class, char.class, Character.class,
double.class, Double.class, float.class, Float.class, int.class, Integer.class,
long.class, Long.class, short.class, Short.class, String.class, Object.class};
static {
for (Class<?> preCachedClass : CACHED_COMMON_TYPES) {
commonTypesCache.put(preCachedClass, valueOf(preCachedClass));
}
}
//最终要转换的类型
private final Class<?> type;
//类型解析器
private final ResolvableType resolvableType;
private final AnnotatedElementAdapter annotatedElement;
}
10.4.1 构造方法
/**
* Create a new type descriptor from a {@link Property}.
* <p>Use this constructor when a source or target conversion point is a
* property on a Java class.
* @param property the property
*/
public TypeDescriptor(Property property) {
Assert.notNull(property, "Property must not be null");
//获取解析当前方法参数的类型解析器
this.resolvableType = ResolvableType.forMethodParameter(property.getMethodParameter());
/**
* 类型解析器解析方法参数的类型
* 上一步调用forMethodParameter的时候就已经将类型解析出来了
* 例如解析List<User>这种属性,它的类型是java.util.List<com.lx.converter.domain.User>
* 这一步只不过验证是否解析成功,解析成功使用上一步解析出来的resolved,
* 否则使用property.getType()(最终使用标准反射获取MethodParameter的类型)
*/
this.type = this.resolvableType.resolve(property.getType());
//属性注解信息
this.annotatedElement = new AnnotatedElementAdapter(property.getAnnotations());
}
ResolvableType
类型解析器,里面有两个关键属性。
public class ResolvableType implements Serializable {
/**
* The underlying Java type being managed.
* 这个会保存泛型信息
* 例如解析List<User>这种属性,它里面会保存java.util.List<com.lx.converter.domain.User>
*/
private final Type type;
/**
* 保存的是最终被转换的类型的clazz对象
* 例如解析List<User>这种属性,它的值就是java.util.List.class
*/
@Nullable
private Class<?> resolved;
/**
* Resolve this type to a {@link java.lang.Class}, returning the specified
* {@code fallback} if the type cannot be resolved. This method will consider bounds
* of {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
* direct resolution fails; however, bounds of {@code Object.class} will be ignored.
* @param fallback the fallback class to use if resolution fails
* @return the resolved {@link Class} or the {@code fallback}
* @see #resolve()
* @see #resolveGeneric(int...)
* @see #resolveGenerics()
*/
public Class<?> resolve(Class<?> fallback) {
//这一步只不过验证是否解析成功,解析成功使用解析出来的resolved,
//否则使用property.getType()(最终使用标准反射获取MethodParameter的类型)
return (this.resolved != null ? this.resolved : fallback);
}
}
10.4.2 getElementTypeDescriptor()
方法,获取类型中的元素类型
/**
* If this type is an array, returns the array's component type.
* If this type is a {@code Stream}, returns the stream's component type.
* If this type is a {@link Collection} and it is parameterized, returns the Collection's element type.
* If the Collection is not parameterized, returns {@code null} indicating the element type is not declared.
* @return the array component type or Collection element type, or {@code null} if this type is not
* an array type or a {@code java.util.Collection} or if its element type is not parameterized
* @see #elementTypeDescriptor(Object)
*/
@Nullable
public TypeDescriptor getElementTypeDescriptor() {
if (getResolvableType().isArray()) {
return new TypeDescriptor(getResolvableType().getComponentType(), null, getAnnotations());
}
if (Stream.class.isAssignableFrom(getType())) {
return getRelatedIfResolvable(this, getResolvableType().as(Stream.class).getGeneric(0));
}
return getRelatedIfResolvable(this, getResolvableType().asCollection().getGeneric(0));
}
- 如果类型是一个数组,那么就返回数组的组件类型
- 如果类型是一个
Stream
,那么就返回Stream
的组件类型- 如果类型是一个
Collection
并且已经参数化了,那么就返回Collection
集合元素的类型- 其他情况均返回
null