Skip to content

Commit e668d80

Browse files
committed
DATAJPA-845 - Avoid unnecessary lookups of PersistenceProvider.
To prevent multiple attempts of class loading down stream for multiple lookup calls to fromEntityManager(…) or fromMetamodel(…). We now avoid the repeated lookups of a PersistenceProvider instance by reusing a canonical one created in CreateQueryLookupStrategy. Instead of looking up the PersistenceProvider for every entity again, we now look it up once in the JpaMappingContext for reuse on all JpaPersistentEntity instances. Original pull request: #161.
1 parent b04e0f0 commit e668d80

File tree

8 files changed

+102
-53
lines changed

8 files changed

+102
-53
lines changed

src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012 the original author or authors.
2+
* Copyright 2012-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
import javax.persistence.metamodel.ManagedType;
2323
import javax.persistence.metamodel.Metamodel;
2424

25+
import org.springframework.data.jpa.provider.PersistenceProvider;
2526
import org.springframework.data.mapping.context.AbstractMappingContext;
2627
import org.springframework.data.mapping.context.MappingContext;
2728
import org.springframework.data.mapping.model.SimpleTypeHolder;
@@ -34,10 +35,11 @@
3435
* @author Oliver Gierke
3536
* @since 1.3
3637
*/
37-
public class JpaMetamodelMappingContext extends
38-
AbstractMappingContext<JpaPersistentEntityImpl<?>, JpaPersistentProperty> {
38+
public class JpaMetamodelMappingContext
39+
extends AbstractMappingContext<JpaPersistentEntityImpl<?>, JpaPersistentProperty> {
3940

4041
private final Set<Metamodel> models;
42+
private final PersistenceProvider persistenceProvider;
4143

4244
/**
4345
* Creates a new JPA {@link Metamodel} based {@link MappingContext}.
@@ -50,6 +52,7 @@ public JpaMetamodelMappingContext(Set<Metamodel> models) {
5052
Assert.notEmpty(models, "At least one JPA metamodel must be present!");
5153

5254
this.models = models;
55+
this.persistenceProvider = PersistenceProvider.fromMetamodel(models.iterator().next());
5356
}
5457

5558
/*
@@ -58,7 +61,7 @@ public JpaMetamodelMappingContext(Set<Metamodel> models) {
5861
*/
5962
@Override
6063
protected <T> JpaPersistentEntityImpl<?> createPersistentEntity(TypeInformation<T> typeInformation) {
61-
return new JpaPersistentEntityImpl<T>(typeInformation, getMetamodelFor(typeInformation.getType()));
64+
return new JpaPersistentEntityImpl<T>(typeInformation, persistenceProvider);
6265
}
6366

6467
/*

src/main/java/org/springframework/data/jpa/mapping/JpaPersistentEntityImpl.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2014 the original author or authors.
2+
* Copyright 2012-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,10 +17,7 @@
1717

1818
import java.util.Comparator;
1919

20-
import javax.persistence.metamodel.Metamodel;
21-
2220
import org.springframework.data.annotation.Version;
23-
import org.springframework.data.jpa.provider.PersistenceProvider;
2421
import org.springframework.data.jpa.provider.ProxyIdAccessor;
2522
import org.springframework.data.mapping.IdentifierAccessor;
2623
import org.springframework.data.mapping.model.BasicPersistentEntity;
@@ -48,14 +45,14 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
4845
* Creates a new {@link JpaPersistentEntityImpl} using the given {@link TypeInformation} and {@link Comparator}.
4946
*
5047
* @param information must not be {@literal null}.
51-
* @param metamodel must not be {@literal null}.
48+
* @param proxyIdAccessor must not be {@literal null}.
5249
*/
53-
public JpaPersistentEntityImpl(TypeInformation<T> information, Metamodel metamodel) {
50+
public JpaPersistentEntityImpl(TypeInformation<T> information, ProxyIdAccessor proxyIdAccessor) {
5451

5552
super(information, null);
5653

57-
Assert.notNull(metamodel, "Metamodel must not be null!");
58-
this.proxyIdAccessor = PersistenceProvider.fromMetamodel(metamodel);
54+
Assert.notNull(proxyIdAccessor, "ProxyIdAccessor must not be null!");
55+
this.proxyIdAccessor = proxyIdAccessor;
5956
}
6057

6158
/*
@@ -116,7 +113,8 @@ private static class JpaProxyAwareIdentifierAccessor extends IdPropertyIdentifie
116113
* @param bean must not be {@literal null}.
117114
* @param proxyIdAccessor must not be {@literal null}.
118115
*/
119-
public JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean, ProxyIdAccessor proxyIdAccessor) {
116+
public JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean,
117+
ProxyIdAccessor proxyIdAccessor) {
120118

121119
super(entity, bean);
122120

@@ -132,8 +130,8 @@ public JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bea
132130
*/
133131
@Override
134132
public Object getIdentifier() {
135-
return proxyIdAccessor.shouldUseAccessorFor(bean) ? proxyIdAccessor.getIdentifierFrom(bean) : super
136-
.getIdentifier();
133+
return proxyIdAccessor.shouldUseAccessorFor(bean) ? proxyIdAccessor.getIdentifierFrom(bean)
134+
: super.getIdentifier();
137135
}
138136
}
139137
}

src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2008-2015 the original author or authors.
2+
* Copyright 2008-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -44,14 +44,15 @@
4444
import org.springframework.data.util.CloseableIterator;
4545
import org.springframework.transaction.support.TransactionSynchronizationManager;
4646
import org.springframework.util.Assert;
47+
import org.springframework.util.ConcurrentReferenceHashMap;
4748

4849
/**
4950
* Enumeration representing persistence providers to be used.
5051
*
5152
* @author Oliver Gierke
5253
* @author Thomas Darimont
5354
*/
54-
public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
55+
public enum PersistenceProvider implements QueryExtractor,ProxyIdAccessor {
5556

5657
/**
5758
* Hibernate persistence provider.
@@ -121,8 +122,8 @@ public CloseableIterator<Object> executeQueryWithResultStream(Query jpaQuery) {
121122
/**
122123
* EclipseLink persistence provider.
123124
*/
124-
ECLIPSELINK(Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE), Collections
125-
.singleton(ECLIPSELINK_JPA_METAMODEL_TYPE)) {
125+
ECLIPSELINK(Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE),
126+
Collections.singleton(ECLIPSELINK_JPA_METAMODEL_TYPE)) {
126127

127128
public String extractQueryString(Query query) {
128129
return ((JpaQuery<?>) query).getDatabaseQuery().getJPQLString();
@@ -263,6 +264,8 @@ static interface Constants {
263264
String OPENJPA_JPA_METAMODEL_TYPE = "org.apache.openjpa.persistence.meta.MetamodelImpl";
264265
}
265266

267+
private static ConcurrentReferenceHashMap<Class<?>, PersistenceProvider> CACHE = new ConcurrentReferenceHashMap<Class<?>, PersistenceProvider>();
268+
266269
private final Iterable<String> entityManagerClassNames;
267270
private final Iterable<String> metamodelClassNames;
268271

@@ -287,32 +290,65 @@ private PersistenceProvider(Iterable<String> entityManagerClassNames, Iterable<S
287290
*/
288291
public static PersistenceProvider fromEntityManager(EntityManager em) {
289292

290-
Assert.notNull(em);
293+
Assert.notNull(em, "EntityManager must not be null!");
294+
295+
Class<?> entityManagerType = em.getDelegate().getClass();
296+
PersistenceProvider cachedProvider = CACHE.get(entityManagerType);
297+
298+
if (cachedProvider != null) {
299+
return cachedProvider;
300+
}
291301

292302
for (PersistenceProvider provider : values()) {
293303
for (String entityManagerClassName : provider.entityManagerClassNames) {
294304
if (isEntityManagerOfType(em, entityManagerClassName)) {
295-
return provider;
305+
return cacheAndReturn(entityManagerType, provider);
296306
}
297307
}
298308
}
299309

300-
return GENERIC_JPA;
310+
return cacheAndReturn(entityManagerType, GENERIC_JPA);
301311
}
302312

313+
/**
314+
* Determines the {@link PersistenceProvider} from the given {@link Metamodel}. If no special one can be determined
315+
* {@link #GENERIC_JPA} will be returned.
316+
*
317+
* @param metamodel must not be {@literal null}.
318+
* @return will never be {@literal null}.
319+
*/
303320
public static PersistenceProvider fromMetamodel(Metamodel metamodel) {
304321

305322
Assert.notNull(metamodel, "Metamodel must not be null!");
306323

324+
Class<? extends Metamodel> metamodelType = metamodel.getClass();
325+
PersistenceProvider cachedProvider = CACHE.get(metamodelType);
326+
327+
if (cachedProvider != null) {
328+
return cachedProvider;
329+
}
330+
307331
for (PersistenceProvider provider : values()) {
308332
for (String metamodelClassName : provider.metamodelClassNames) {
309333
if (isMetamodelOfType(metamodel, metamodelClassName)) {
310-
return provider;
334+
return cacheAndReturn(metamodelType, provider);
311335
}
312336
}
313337
}
314338

315-
return GENERIC_JPA;
339+
return cacheAndReturn(metamodelType, GENERIC_JPA);
340+
}
341+
342+
/**
343+
* Caches the given {@link PersistenceProvider} for the given source type.
344+
*
345+
* @param type must not be {@literal null}.
346+
* @param provider must not be {@literal null}.
347+
* @return
348+
*/
349+
private static PersistenceProvider cacheAndReturn(Class<?> type, PersistenceProvider provider) {
350+
CACHE.put(type, provider);
351+
return provider;
316352
}
317353

318354
/*
@@ -348,8 +384,8 @@ public <T> Collection<T> potentiallyConvertEmptyCollection(Collection<T> collect
348384
}
349385

350386
public CloseableIterator<Object> executeQueryWithResultStream(Query jpaQuery) {
351-
throw new UnsupportedOperationException("Streaming results is not implement for this PersistenceProvider: "
352-
+ name());
387+
throw new UnsupportedOperationException(
388+
"Streaming results is not implement for this PersistenceProvider: " + name());
353389
}
354390

355391
/**

src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2008-2013 the original author or authors.
2+
* Copyright 2008-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919

2020
import javax.persistence.EntityManager;
2121

22+
import org.springframework.data.jpa.provider.PersistenceProvider;
2223
import org.springframework.data.jpa.provider.QueryExtractor;
2324
import org.springframework.data.projection.ProjectionFactory;
2425
import org.springframework.data.repository.core.NamedQueries;
@@ -87,15 +88,19 @@ public final RepositoryQuery resolveQuery(Method method, RepositoryMetadata meta
8788
*/
8889
private static class CreateQueryLookupStrategy extends AbstractQueryLookupStrategy {
8990

91+
private final PersistenceProvider persistenceProvider;
92+
9093
public CreateQueryLookupStrategy(EntityManager em, QueryExtractor extractor) {
94+
9195
super(em, extractor);
96+
this.persistenceProvider = PersistenceProvider.fromEntityManager(em);
9297
}
9398

9499
@Override
95100
protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
96101

97102
try {
98-
return new PartTreeJpaQuery(method, em);
103+
return new PartTreeJpaQuery(method, em, persistenceProvider);
99104
} catch (IllegalArgumentException e) {
100105
throw new IllegalArgumentException(
101106
String.format("Could not create query metamodel for method %s!", method.toString()), e);

src/main/java/org/springframework/data/jpa/repository/query/ParameterMetadataProvider.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011-2014 the original author or authors.
2+
* Copyright 2011-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -73,7 +73,6 @@ public ParameterMetadataProvider(CriteriaBuilder builder, ParametersParameterAcc
7373
* @param provider must not be {@literal null}.
7474
*/
7575
public ParameterMetadataProvider(CriteriaBuilder builder, Parameters<?, ?> parameters, PersistenceProvider provider) {
76-
7776
this(builder, null, parameters, provider);
7877
}
7978

@@ -90,9 +89,9 @@ public ParameterMetadataProvider(CriteriaBuilder builder, Parameters<?, ?> param
9089
private ParameterMetadataProvider(CriteriaBuilder builder, Iterator<Object> bindableParameterValues,
9190
Parameters<?, ?> parameters, PersistenceProvider provider) {
9291

93-
Assert.notNull(builder);
94-
Assert.notNull(parameters);
95-
Assert.notNull(provider);
92+
Assert.notNull(builder, "CriteriaBuilder must not be null!");
93+
Assert.notNull(parameters, "Parameters must not be null!");
94+
Assert.notNull(provider, "PesistenceProvider must not be null!");
9695

9796
this.builder = builder;
9897
this.parameters = parameters.getBindableParameters().iterator();

src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2008-2014 the original author or authors.
2+
* Copyright 2008-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -54,18 +54,19 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
5454
* @param factory must not be {@literal null}.
5555
* @param em must not be {@literal null}.
5656
*/
57-
public PartTreeJpaQuery(JpaQueryMethod method, EntityManager em) {
57+
public PartTreeJpaQuery(JpaQueryMethod method, EntityManager em, PersistenceProvider persistenceProvider) {
5858

5959
super(method, em);
60+
6061
this.em = em;
6162
this.domainClass = method.getEntityInformation().getJavaType();
6263
this.tree = new PartTree(method.getName(), domainClass);
6364
this.parameters = method.getParameters();
6465

6566
boolean recreationRequired = parameters.hasDynamicProjection() || parameters.potentiallySortsDynamically();
6667

67-
this.countQuery = new CountQueryPreparer(recreationRequired);
68-
this.query = tree.isCountProjection() ? countQuery : new QueryPreparer(recreationRequired);
68+
this.countQuery = new CountQueryPreparer(persistenceProvider, recreationRequired);
69+
this.query = tree.isCountProjection() ? countQuery : new QueryPreparer(persistenceProvider, recreationRequired);
6970
}
7071

7172
/*
@@ -106,10 +107,14 @@ private class QueryPreparer {
106107

107108
private final CriteriaQuery<?> cachedCriteriaQuery;
108109
private final List<ParameterMetadata<?>> expressions;
110+
private final PersistenceProvider persistenceProvider;
111+
112+
public QueryPreparer(PersistenceProvider persistenceProvider, boolean recreateQueries) {
113+
114+
this.persistenceProvider = persistenceProvider;
109115

110-
public QueryPreparer(boolean recreateQueries) {
116+
JpaQueryCreator creator = createCreator(null, persistenceProvider);
111117

112-
JpaQueryCreator creator = createCreator(null);
113118
this.cachedCriteriaQuery = recreateQueries ? null : creator.createQuery();
114119
this.expressions = recreateQueries ? null : creator.getParameterExpressions();
115120
}
@@ -127,7 +132,7 @@ public Query createQuery(Object[] values) {
127132
ParametersParameterAccessor accessor = new ParametersParameterAccessor(parameters, values);
128133

129134
if (cachedCriteriaQuery == null || accessor.hasBindableNullValue()) {
130-
JpaQueryCreator creator = createCreator(accessor);
135+
JpaQueryCreator creator = createCreator(accessor, persistenceProvider);
131136
criteriaQuery = creator.createQuery(getDynamicSort(values));
132137
expressions = creator.getParameterExpressions();
133138
}
@@ -186,11 +191,11 @@ private TypedQuery<?> createQuery(CriteriaQuery<?> criteriaQuery) {
186191
return getEntityManager().createQuery(criteriaQuery);
187192
}
188193

189-
protected JpaQueryCreator createCreator(ParametersParameterAccessor accessor) {
194+
protected JpaQueryCreator createCreator(ParametersParameterAccessor accessor,
195+
PersistenceProvider persistenceProvider) {
190196

191197
EntityManager entityManager = getEntityManager();
192198
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
193-
PersistenceProvider persistenceProvider = PersistenceProvider.fromEntityManager(entityManager);
194199

195200
ParameterMetadataProvider provider = accessor == null
196201
? new ParameterMetadataProvider(builder, parameters, persistenceProvider)
@@ -232,20 +237,20 @@ private Sort getDynamicSort(Object[] values) {
232237
*/
233238
private class CountQueryPreparer extends QueryPreparer {
234239

235-
public CountQueryPreparer(boolean recreateQueries) {
236-
super(recreateQueries);
240+
public CountQueryPreparer(PersistenceProvider persistenceProvider, boolean recreateQueries) {
241+
super(persistenceProvider, recreateQueries);
237242
}
238243

239244
/*
240245
* (non-Javadoc)
241-
* @see org.springframework.data.jpa.repository.query.PartTreeJpaQuery.QueryPreparer#createCreator(org.springframework.data.repository.query.ParametersParameterAccessor)
246+
* @see org.springframework.data.jpa.repository.query.PartTreeJpaQuery.QueryPreparer#createCreator(org.springframework.data.repository.query.ParametersParameterAccessor, org.springframework.data.jpa.provider.PersistenceProvider)
242247
*/
243248
@Override
244-
protected JpaQueryCreator createCreator(ParametersParameterAccessor accessor) {
249+
protected JpaQueryCreator createCreator(ParametersParameterAccessor accessor,
250+
PersistenceProvider persistenceProvider) {
245251

246252
EntityManager entityManager = getEntityManager();
247253
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
248-
PersistenceProvider persistenceProvider = PersistenceProvider.fromEntityManager(entityManager);
249254

250255
ParameterMetadataProvider provider = accessor == null
251256
? new ParameterMetadataProvider(builder, parameters, persistenceProvider)

0 commit comments

Comments
 (0)