Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 24c31bf

Browse files
christophstroblmp911de
authored andcommitted
Move responsibility for storing method context to dedicated component.
See #3175. Original pull request: #3176
1 parent 323aa60 commit 24c31bf

File tree

8 files changed

+119
-79
lines changed

8 files changed

+119
-79
lines changed

‎src/main/java/org/springframework/data/repository/aot/hint/RepositoryRuntimeHints.java‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818
import java.util.Arrays;
1919
import java.util.Properties;
2020

21+
import org.springframework.aop.SpringProxy;
22+
import org.springframework.aop.framework.Advised;
2123
import org.springframework.aot.hint.MemberCategory;
2224
import org.springframework.aot.hint.RuntimeHints;
2325
import org.springframework.aot.hint.RuntimeHintsRegistrar;
2426
import org.springframework.aot.hint.TypeReference;
2527
import org.springframework.beans.factory.BeanFactory;
28+
import org.springframework.core.DecoratingProxy;
2629
import org.springframework.core.io.InputStreamSource;
2730
import org.springframework.data.domain.Example;
2831
import org.springframework.data.mapping.context.MappingContext;
@@ -99,5 +102,13 @@ public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader)
99102
// annotated queries
100103
hints.proxies().registerJdkProxy( //
101104
TypeReference.of("org.springframework.data.annotation.QueryAnnotation"));
105+
106+
registerSpringProxy(TypeReference.of("org.springframework.data.repository.core.RepositoryMethodContext"), hints);
107+
}
108+
109+
private static void registerSpringProxy(TypeReference type, RuntimeHints runtimeHints) {
110+
111+
runtimeHints.proxies().registerJdkProxy(type, TypeReference.of(SpringProxy.class),
112+
TypeReference.of(Advised.class), TypeReference.of(DecoratingProxy.class));
102113
}
103114
}

‎src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java‎

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
*/
1616
package org.springframework.data.repository.config;
1717

18-
import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.*;
18+
import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR;
19+
import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.generateBeanName;
1920

2021
import java.lang.annotation.Annotation;
2122
import java.util.Collection;
@@ -31,15 +32,12 @@
3132
import org.springframework.beans.factory.support.AbstractBeanDefinition;
3233
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3334
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
34-
import org.springframework.beans.factory.support.RootBeanDefinition;
3535
import org.springframework.core.annotation.AnnotationUtils;
3636
import org.springframework.core.io.ResourceLoader;
3737
import org.springframework.core.log.LogMessage;
3838
import org.springframework.dao.InvalidDataAccessApiUsageException;
3939
import org.springframework.data.repository.core.RepositoryMetadata;
40-
import org.springframework.data.repository.core.RepositoryMethodContext;
4140
import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
42-
import org.springframework.data.repository.core.support.DefaultRepositoryMethodContext;
4341
import org.springframework.lang.Nullable;
4442
import org.springframework.util.Assert;
4543
import org.springframework.util.StringUtils;
@@ -112,13 +110,7 @@ public String getDefaultNamedQueryLocation() {
112110

113111
@Override
114112
public void registerBeansForRoot(BeanDefinitionRegistry registry,
115-
RepositoryConfigurationSource configurationSource) {
116-
117-
// A proxy RepositoryMethodContext for dependency injection
118-
registerIfNotAlreadyRegistered(
119-
() -> new RootBeanDefinition(RepositoryMethodContext.class, DefaultRepositoryMethodContext::getInjectionProxy),
120-
registry, "repositoryMethodContextFactory", configurationSource);
121-
}
113+
RepositoryConfigurationSource configurationSource) {}
122114

123115
/**
124116
* Returns the prefix of the module to be used to create the default location for Spring Data named queries.

‎src/main/java/org/springframework/data/repository/core/RepositoryMethodContext.java‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
/**
2121
* Interface containing methods and value objects to obtain information about the current repository method invocation.
2222
* <p>
23-
* The {@link #currentMethod()} method is usable if the repository factory is configured to expose the current
24-
* repository method metadata (not the default). It returns the invoked repository method. Target objects or advice can
25-
* use this to make advised calls.
23+
* The {@link #getMetadata()} method is usable if the repository factory is configured to expose the current repository
24+
* method metadata (not the default). It returns the invoked repository method. Target objects or advice can use this to
25+
* make advised calls.
2626
* <p>
2727
* Spring Data's framework does not expose method metadata by default, as there is a performance cost in doing so.
2828
* <p>
@@ -50,7 +50,7 @@ public interface RepositoryMethodContext {
5050
* The method object represents the method as being invoked on the repository interface. It doesn't match the backing
5151
* repository implementation in case the method invocation is delegated to an implementation method.
5252
*
53-
* @return the current method, will never be {@literal null}..
53+
* @return the current method, will never be {@literal null}.
5454
*/
5555
Method getMethod();
5656
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.repository.core;
17+
18+
import org.springframework.core.NamedThreadLocal;
19+
import org.springframework.lang.Nullable;
20+
21+
/**
22+
* @author Christoph Strobl
23+
* @since 3.4.0
24+
*/
25+
public class RepositoryMethodContextHolder {
26+
27+
private static ContextProvider contextSupplier;
28+
29+
static {
30+
contextSupplier = new ThreadLocalContextProvider();
31+
}
32+
33+
@Nullable
34+
public static RepositoryMethodContext setContext(@Nullable RepositoryMethodContext context) {
35+
return contextSupplier.set(context);
36+
}
37+
38+
@Nullable
39+
public static RepositoryMethodContext current() {
40+
return contextSupplier.get();
41+
}
42+
43+
public static void clearContext() {
44+
contextSupplier.clear();
45+
}
46+
47+
interface ContextProvider {
48+
49+
@Nullable
50+
RepositoryMethodContext get();
51+
52+
@Nullable
53+
RepositoryMethodContext set(@Nullable RepositoryMethodContext context);
54+
55+
void clear();
56+
}
57+
58+
static class ThreadLocalContextProvider implements ContextProvider {
59+
60+
/**
61+
* ThreadLocal holder for repository method associated with this thread. Will contain {@code null} unless the
62+
* "exposeMetadata" property on the controlling repository factory configuration has been set to "true".
63+
*/
64+
private static final ThreadLocal<RepositoryMethodContext> currentMethod = new NamedThreadLocal<>(
65+
"Current Repository Method");
66+
67+
@Override
68+
@Nullable
69+
public RepositoryMethodContext get() {
70+
return currentMethod.get();
71+
}
72+
73+
public void clear() {
74+
currentMethod.remove();
75+
}
76+
77+
@Override
78+
@Nullable
79+
public RepositoryMethodContext set(@Nullable RepositoryMethodContext context) {
80+
81+
RepositoryMethodContext old = currentMethod.get();
82+
83+
if (context != null) {
84+
currentMethod.set(context);
85+
} else {
86+
currentMethod.remove();
87+
}
88+
89+
return old;
90+
}
91+
}
92+
}

‎src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryMethodContext.java‎

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@
1717

1818
import java.lang.reflect.Method;
1919

20-
import org.springframework.aop.framework.ProxyFactory;
21-
import org.springframework.core.NamedThreadLocal;
2220
import org.springframework.data.repository.core.RepositoryMetadata;
2321
import org.springframework.data.repository.core.RepositoryMethodContext;
24-
import org.springframework.lang.Nullable;
2522
import org.springframework.util.Assert;
2623

2724
/**
@@ -34,13 +31,6 @@
3431
*/
3532
public class DefaultRepositoryMethodContext implements RepositoryMethodContext {
3633

37-
/**
38-
* ThreadLocal holder for repository method associated with this thread. Will contain {@code null} unless the
39-
* "exposeMetadata" property on the controlling repository factory configuration has been set to "true".
40-
*/
41-
private static final ThreadLocal<RepositoryMethodContext> currentMethod = new NamedThreadLocal<>(
42-
"Current Repository Method");
43-
4434
private final RepositoryMetadata repositoryMetadata;
4535
private final Method method;
4636

@@ -64,36 +54,6 @@ public static RepositoryMethodContext forMethod(Method method) {
6454
method);
6555
}
6656

67-
/**
68-
* Creates a proxy {@link RepositoryMethodContext} instance suitable for dependency injection.
69-
*
70-
* @return will never be {@literal null}.
71-
*/
72-
public static RepositoryMethodContext getInjectionProxy() {
73-
74-
return ProxyFactory.getProxy(RepositoryMethodContext.class,
75-
new DynamicLookupTargetSource<>(RepositoryMethodContext.class, () -> getInstance()));
76-
}
77-
78-
@Nullable
79-
static RepositoryMethodContext getInstance() {
80-
return currentMethod.get();
81-
}
82-
83-
@Nullable
84-
static RepositoryMethodContext setMetadata(@Nullable RepositoryMethodContext metadata) {
85-
86-
RepositoryMethodContext old = currentMethod.get();
87-
88-
if (metadata != null) {
89-
currentMethod.set(metadata);
90-
} else {
91-
currentMethod.remove();
92-
}
93-
94-
return old;
95-
}
96-
9757
@Override
9858
public RepositoryMetadata getMetadata() {
9959
return repositoryMetadata;

‎src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import org.springframework.data.repository.core.RepositoryInformation;
5858
import org.springframework.data.repository.core.RepositoryMetadata;
5959
import org.springframework.data.repository.core.RepositoryMethodContext;
60+
import org.springframework.data.repository.core.RepositoryMethodContextHolder;
6061
import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments;
6162
import org.springframework.data.repository.core.support.RepositoryInvocationMulticaster.DefaultRepositoryInvocationMulticaster;
6263
import org.springframework.data.repository.core.support.RepositoryInvocationMulticaster.NoOpRepositoryInvocationMulticaster;
@@ -776,13 +777,13 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
776777

777778
try {
778779

779-
oldMetadata = DefaultRepositoryMethodContext
780-
.setMetadata(new DefaultRepositoryMethodContext(repositoryMetadata, invocation.getMethod()));
780+
oldMetadata = RepositoryMethodContextHolder
781+
.setContext(new DefaultRepositoryMethodContext(repositoryMetadata, invocation.getMethod()));
781782

782783
return invocation.proceed();
783784

784785
} finally {
785-
DefaultRepositoryMethodContext.setMetadata(oldMetadata);
786+
RepositoryMethodContextHolder.setContext(oldMetadata);
786787
}
787788
}
788789
}

‎src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -276,24 +276,6 @@ void considersGenericLength() {
276276
assertThat(it.getGeneric(1).resolve()).isEqualTo(Person.class);
277277
}
278278

279-
@Test // GH-3175
280-
void registersRepositoryMethodContextForInjection() {
281-
282-
var environment = new StandardEnvironment();
283-
var context = new GenericApplicationContext();
284-
context.registerBean("fragment", MyFragmentImpl.class);
285-
286-
RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource(
287-
AnnotationMetadata.introspect(TestConfig.class), EnableRepositories.class, context, environment,
288-
context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator());
289-
290-
var delegate = new RepositoryConfigurationDelegate(configSource, context, environment);
291-
292-
delegate.registerRepositoriesIn(context, extension);
293-
294-
assertThat(context.containsBeanDefinition("repositoryMethodContextFactory")).isTrue();
295-
}
296-
297279
private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class<?> configClass) {
298280

299281
var context = new AnnotationConfigApplicationContext(configClass);

‎src/test/java/org/springframework/data/repository/core/support/RepositoryFactorySupportUnitTests.java‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
import org.springframework.data.repository.core.NamedQueries;
5858
import org.springframework.data.repository.core.RepositoryInformation;
5959
import org.springframework.data.repository.core.RepositoryMetadata;
60+
import org.springframework.data.repository.core.RepositoryMethodContext;
61+
import org.springframework.data.repository.core.RepositoryMethodContextHolder;
6062
import org.springframework.data.repository.core.support.DummyRepositoryFactory.MyRepositoryQuery;
6163
import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments;
6264
import org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocation;
@@ -254,7 +256,7 @@ void capturesRepositoryMetadata() {
254256
record Metadata(RepositoryMethodContext context, MethodInvocation methodInvocation) {}
255257

256258
when(factory.queryOne.execute(any(Object[].class)))
257-
.then(invocation -> new Metadata(DefaultRepositoryMethodContext.getInstance(),
259+
.then(invocation -> new Metadata(RepositoryMethodContextHolder.current(),
258260
ExposeInvocationInterceptor.currentInvocation()));
259261

260262
factory.setExposeMetadata(true);
@@ -277,7 +279,7 @@ record Metadata(RepositoryMethodContext context, MethodInvocation methodInvocati
277279
}
278280

279281
when(factory.queryOne.execute(any(Object[].class)))
280-
.then(invocation -> new Metadata(RepositoryMethodContext.currentMethod(),
282+
.then(invocation -> new Metadata(RepositoryMethodContextHolder.current(),
281283
ExposeInvocationInterceptor.currentInvocation()));
282284

283285
var repository = factory.getRepository(ObjectRepository.class, new RepositoryMetadataAccess() {});
@@ -287,7 +289,7 @@ record Metadata(RepositoryMethodContext context, MethodInvocation methodInvocati
287289

288290
Metadata metadata = (Metadata) metadataByLastname;
289291
assertThat(metadata.context().getMethod().getName()).isEqualTo("findMetadataByLastname");
290-
assertThat(metadata.context().getRepository().getDomainType()).isEqualTo(Object.class);
292+
assertThat(metadata.context().getMetadata().getDomainType()).isEqualTo(Object.class);
291293
assertThat(metadata.methodInvocation().getMethod().getName()).isEqualTo("findMetadataByLastname");
292294
}
293295

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /