DATACMNS-332 - Performance improvements in conversion subsystem hotspots.

Added caching to DefaultTypeMapper, SimpleTypeInformationMapper, BasicPersistentEntity and PreferredConstructor as these seem to be performance hotspots on the reading side of object conversion.
This commit is contained in:
Oliver Gierke
2013-05-17 13:58:14 +02:00
parent a8b912c09f
commit a9abb40fbd
6 changed files with 140 additions and 20 deletions

View File

@@ -19,6 +19,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.context.MappingContext;
@@ -38,6 +40,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
private final TypeAliasAccessor<S> accessor;
private final List<? extends TypeInformationMapper> mappers;
private final Map<Object, TypeInformation<?>> typeCache;
/**
* Creates a new {@link DefaultTypeMapper} using the given {@link TypeAliasAccessor}. It will use a
@@ -84,6 +87,7 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
this.mappers = Collections.unmodifiableList(mappers);
this.accessor = accessor;
this.typeCache = new ConcurrentHashMap<Object, TypeInformation<?>>();
}
/*
@@ -93,21 +97,37 @@ public class DefaultTypeMapper<S> implements TypeMapper<S> {
public TypeInformation<?> readType(S source) {
Assert.notNull(source);
Object alias = accessor.readAliasFrom(source);
if (alias == null) {
return null;
Object alias = accessor.readAliasFrom(source);
return alias == null ? null : getFromCacheOrCreate(alias);
}
/**
* Tries to lookup a {@link TypeInformation} for the given alias from the cache and return it if found. If none is
* found it'll consult the {@link TypeInformationMapper}s and cache the value found.
*
* @param alias
* @return
*/
private TypeInformation<?> getFromCacheOrCreate(Object alias) {
TypeInformation<?> typeInformation = typeCache.get(alias);
if (typeInformation != null) {
return typeInformation;
}
for (TypeInformationMapper mapper : mappers) {
TypeInformation<?> type = mapper.resolveTypeFrom(alias);
if (type != null) {
return type;
typeInformation = mapper.resolveTypeFrom(alias);
if (typeInformation != null) {
typeCache.put(alias, typeInformation);
return typeInformation;
}
}
return null;
return typeInformation;
}
/*

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.data.convert;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.ClassUtils;
@@ -30,6 +33,7 @@ import org.springframework.util.StringUtils;
public class SimpleTypeInformationMapper implements TypeInformationMapper {
public static final SimpleTypeInformationMapper INSTANCE = new SimpleTypeInformationMapper();
private static final Map<String, TypeInformation<?>> cache = new ConcurrentHashMap<String, TypeInformation<?>>();
/**
* Returns the {@link TypeInformation} that shall be used when the given {@link String} value is found as type hint.
@@ -52,11 +56,23 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper {
return null;
}
TypeInformation<?> information = cache.get(value);
if (information != null) {
return information;
}
try {
return ClassTypeInformation.from(ClassUtils.forName(value, null));
information = ClassTypeInformation.from(ClassUtils.forName(value, null));
} catch (ClassNotFoundException e) {
return null;
}
if (information != null) {
cache.put(value, information);
}
return information;
}
/**
@@ -67,7 +83,6 @@ public class SimpleTypeInformationMapper implements TypeInformationMapper {
* @return the String representation to be stored or {@literal null} if no type information shall be stored.
*/
public String createAliasFor(TypeInformation<?> type) {
return type.getType().getName();
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2011-2013 by the original author(s).
* Copyright 2011-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,6 +21,8 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.PersistenceConstructor;
@@ -39,6 +41,7 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
private final Constructor<T> constructor;
private final List<Parameter<Object, P>> parameters;
private final Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new ConcurrentHashMap<PersistentProperty<?>, Boolean>();
/**
* Creates a new {@link PreferredConstructor} from the given {@link Constructor} and {@link Parameter}s.
@@ -114,12 +117,20 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
Assert.notNull(property);
Boolean cached = isPropertyParameterCache.get(property);
if (cached != null) {
return cached;
}
for (Parameter<?, P> parameter : parameters) {
if (parameter.maps(property)) {
isPropertyParameterCache.put(property, true);
return true;
}
}
isPropertyParameterCache.put(property, false);
return false;
}

View File

@@ -17,7 +17,9 @@ package org.springframework.data.mapping.model;
import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -46,6 +48,8 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
private final Set<P> properties;
private final Set<Association<P>> associations;
private final Map<String, P> propertyCache = new HashMap<String, P>();
private P idProperty;
private P versionProperty;
@@ -157,6 +161,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
Assert.notNull(property);
properties.add(property);
propertyCache.put(property.getName(), property);
if (property.isIdProperty()) {
@@ -193,14 +198,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
* @see org.springframework.data.mapping.PersistentEntity#getPersistentProperty(java.lang.String)
*/
public P getPersistentProperty(String name) {
for (P property : properties) {
if (property.getName().equals(name)) {
return property;
}
}
return null;
return propertyCache.get(name);
}
/*