Skip to content

Commit 8416972

Browse files
committed
Fix caching of RepositoryMethodKey
1 parent dab1638 commit 8416972

File tree

3 files changed

+81
-22
lines changed

3 files changed

+81
-22
lines changed

data-jdbc/src/test/groovy/io/micronaut/data/jdbc/h2/H2RepositoryScopeSpec.groovy

+65
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
*/
1616
package io.micronaut.data.jdbc.h2
1717

18+
import groovy.transform.Memoized
1819
import io.micronaut.context.BeanContext
20+
import io.micronaut.context.annotation.Prototype
21+
import io.micronaut.data.runtime.intercept.DataInterceptorResolver
1922
import io.micronaut.test.extensions.spock.annotation.MicronautTest
2023
import jakarta.inject.Inject
2124
import spock.lang.Shared
@@ -43,4 +46,66 @@ class H2RepositoryScopeSpec extends Specification {
4346
then:
4447
instance1.is(instance2)
4548
}
49+
50+
void "test no memory leak 1"() {
51+
when:
52+
def dataInterceptor = getDataInterceptor()
53+
def instance = beanContext.getBean(H2BookRepository)
54+
then:
55+
instance.deleteAll()
56+
if (i % 1000 == 0) {
57+
System.gc()
58+
}
59+
dataInterceptor.@interceptors.size() < 10000
60+
where:
61+
i << (1..30000)
62+
}
63+
64+
void "test no memory leak 2"() {
65+
when:
66+
def dataInterceptor = getDataInterceptor()
67+
def instance = bookRepository
68+
then:
69+
instance.deleteAll()
70+
if (i % 1000 == 0) {
71+
System.gc()
72+
}
73+
dataInterceptor.@interceptors.size() < 10000
74+
where:
75+
i << (1..30000)
76+
}
77+
78+
void "test no memory leak 3"() {
79+
when:
80+
def dataInterceptor = getDataInterceptor()
81+
def myService = beanContext.getBean(MyPrototypeService)
82+
then:
83+
myService.bookRepository.deleteAll()
84+
if (i % 1000 == 0) {
85+
System.gc()
86+
}
87+
dataInterceptor.@interceptors.size() < 10000
88+
where:
89+
i << (1..30000)
90+
}
91+
92+
@Memoized
93+
private DataInterceptorResolver getDataInterceptor() {
94+
return beanContext.getBean(DataInterceptorResolver)
95+
}
96+
97+
@Memoized
98+
H2BookRepository getBookRepository() {
99+
beanContext.getBean(H2BookRepository)
100+
}
101+
102+
@Prototype
103+
static class MyPrototypeService {
104+
105+
final H2BookRepository bookRepository
106+
107+
MyPrototypeService(H2BookRepository bookRepository) {
108+
this.bookRepository = bookRepository
109+
}
110+
}
46111
}

data-model/src/main/java/io/micronaut/data/intercept/RepositoryMethodKey.java

+15-21
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
package io.micronaut.data.intercept;
1717

1818
import io.micronaut.core.annotation.Internal;
19+
import io.micronaut.core.type.Argument;
1920
import io.micronaut.inject.ExecutableMethod;
2021

22+
import java.util.Arrays;
2123
import java.util.Objects;
2224

2325
/**
@@ -28,44 +30,36 @@
2830
*/
2931
@Internal
3032
public final class RepositoryMethodKey {
31-
private final Object repository;
32-
private final ExecutableMethod<?, ?> method;
33+
private final Class<?> repositoryClass;
34+
private final String repositoryMethodName;
35+
private final Argument<?>[] repositoryMethodArguments;
3336
private final int hashCode;
3437

3538
/**
3639
* @param repository The repository instance
3740
* @param method The method
3841
*/
3942
public RepositoryMethodKey(Object repository, ExecutableMethod<?, ?> method) {
40-
this.repository = repository;
41-
this.method = method;
42-
this.hashCode = Objects.hash(repository, method);
43+
this.repositoryClass = repository.getClass();
44+
this.repositoryMethodName = method.getName();
45+
this.repositoryMethodArguments = method.getArguments();
46+
this.hashCode = Objects.hash(repositoryClass, repositoryMethodName, repositoryMethodArguments.length);
4347
}
4448

45-
public Object repository() {
46-
return repository;
47-
}
48-
49-
public ExecutableMethod<?, ?> method() {
50-
return method;
51-
}
5249

5350
@Override
54-
public boolean equals(Object obj) {
55-
if (obj == this) {
56-
return true;
57-
}
58-
if (obj == null || obj.getClass() != this.getClass()) {
51+
public boolean equals(Object o) {
52+
if (o == null || getClass() != o.getClass()) {
5953
return false;
6054
}
61-
var that = (RepositoryMethodKey) obj;
62-
return Objects.equals(this.repository, that.repository) &&
63-
Objects.equals(this.method, that.method);
55+
RepositoryMethodKey that = (RepositoryMethodKey) o;
56+
return Objects.equals(repositoryClass, that.repositoryClass)
57+
&& Objects.equals(repositoryMethodName, that.repositoryMethodName)
58+
&& Objects.deepEquals(repositoryMethodArguments, that.repositoryMethodArguments);
6459
}
6560

6661
@Override
6762
public int hashCode() {
6863
return hashCode;
6964
}
70-
7165
}

data-runtime/src/main/java/io/micronaut/data/runtime/intercept/DataInterceptorResolver.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
*/
5050
@Internal
5151
@Singleton
52-
final class DataInterceptorResolver {
52+
public final class DataInterceptorResolver {
5353

5454
private final RepositoryOperationsRegistry repositoryOperationsRegistry;
5555
@Nullable

0 commit comments

Comments
 (0)