Skip to content

Commit c121a9e

Browse files
authored
Merge pull request apolloconfig#1676 from nobodyiam/fix-1670
use weak reference to hold bean objects so that they could be garbage collected
2 parents d93a6ba + 790ee89 commit c121a9e

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValue.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ctrip.framework.apollo.spring.property;
22

3+
import java.lang.ref.WeakReference;
34
import java.lang.reflect.Field;
45
import java.lang.reflect.InvocationTargetException;
56
import java.lang.reflect.Method;
@@ -16,7 +17,7 @@ public class SpringValue {
1617

1718
private MethodParameter methodParameter;
1819
private Field field;
19-
private Object bean;
20+
private WeakReference<Object> beanRef;
2021
private String beanName;
2122
private String key;
2223
private String placeholder;
@@ -25,7 +26,7 @@ public class SpringValue {
2526
private boolean isJson;
2627

2728
public SpringValue(String key, String placeholder, Object bean, String beanName, Field field, boolean isJson) {
28-
this.bean = bean;
29+
this.beanRef = new WeakReference<>(bean);
2930
this.beanName = beanName;
3031
this.field = field;
3132
this.key = key;
@@ -38,7 +39,7 @@ public SpringValue(String key, String placeholder, Object bean, String beanName,
3839
}
3940

4041
public SpringValue(String key, String placeholder, Object bean, String beanName, Method method, boolean isJson) {
41-
this.bean = bean;
42+
this.beanRef = new WeakReference<>(bean);
4243
this.beanName = beanName;
4344
this.methodParameter = new MethodParameter(method, 0);
4445
this.key = key;
@@ -60,6 +61,10 @@ public void update(Object newVal) throws IllegalAccessException, InvocationTarge
6061
}
6162

6263
private void injectField(Object newVal) throws IllegalAccessException {
64+
Object bean = beanRef.get();
65+
if (bean == null) {
66+
return;
67+
}
6368
boolean accessible = field.isAccessible();
6469
field.setAccessible(true);
6570
field.set(bean, newVal);
@@ -68,6 +73,10 @@ private void injectField(Object newVal) throws IllegalAccessException {
6873

6974
private void injectMethod(Object newVal)
7075
throws InvocationTargetException, IllegalAccessException {
76+
Object bean = beanRef.get();
77+
if (bean == null) {
78+
return;
79+
}
7180
methodParameter.getMethod().invoke(bean, newVal);
7281
}
7382

@@ -103,8 +112,16 @@ public boolean isJson() {
103112
return isJson;
104113
}
105114

115+
boolean isTargetBeanValid() {
116+
return beanRef.get() != null;
117+
}
118+
106119
@Override
107120
public String toString() {
121+
Object bean = beanRef.get();
122+
if (bean == null) {
123+
return "";
124+
}
108125
if (isField()) {
109126
return String
110127
.format("key: %s, beanName: %s, field: %s.%s", key, beanName, bean.getClass().getName(), field.getName());

apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueRegistry.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
package com.ctrip.framework.apollo.spring.property;
22

3+
import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
34
import com.google.common.collect.LinkedListMultimap;
45
import com.google.common.collect.Maps;
56
import com.google.common.collect.Multimap;
67
import java.util.Collection;
8+
import java.util.Iterator;
79
import java.util.Map;
10+
import java.util.Map.Entry;
11+
import java.util.concurrent.Executors;
12+
import java.util.concurrent.TimeUnit;
13+
import java.util.concurrent.atomic.AtomicBoolean;
814
import org.springframework.beans.factory.BeanFactory;
915

1016
public class SpringValueRegistry {
11-
17+
private static final long CLEAN_INTERVAL_IN_SECONDS = 5;
1218
private final Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap();
19+
private final AtomicBoolean initialized = new AtomicBoolean(false);
1320
private final Object LOCK = new Object();
1421

1522
public void register(BeanFactory beanFactory, String key, SpringValue springValue) {
@@ -22,6 +29,11 @@ public void register(BeanFactory beanFactory, String key, SpringValue springValu
2229
}
2330

2431
registry.get(beanFactory).put(key, springValue);
32+
33+
// lazy initialize
34+
if (initialized.compareAndSet(false, true)) {
35+
initialize();
36+
}
2537
}
2638

2739
public Collection<SpringValue> get(BeanFactory beanFactory, String key) {
@@ -31,4 +43,33 @@ public Collection<SpringValue> get(BeanFactory beanFactory, String key) {
3143
}
3244
return beanFactorySpringValues.get(key);
3345
}
46+
47+
private void initialize() {
48+
Executors.newSingleThreadScheduledExecutor(ApolloThreadFactory.create("SpringValueRegistry", true)).scheduleAtFixedRate(
49+
new Runnable() {
50+
@Override
51+
public void run() {
52+
try {
53+
scanAndClean();
54+
} catch (Throwable ex) {
55+
ex.printStackTrace();
56+
}
57+
}
58+
}, CLEAN_INTERVAL_IN_SECONDS, CLEAN_INTERVAL_IN_SECONDS, TimeUnit.SECONDS);
59+
}
60+
61+
private void scanAndClean() {
62+
Iterator<Multimap<String, SpringValue>> iterator = registry.values().iterator();
63+
while (!Thread.currentThread().isInterrupted() && iterator.hasNext()) {
64+
Multimap<String, SpringValue> springValues = iterator.next();
65+
Iterator<Entry<String, SpringValue>> springValueIterator = springValues.entries().iterator();
66+
while (springValueIterator.hasNext()) {
67+
Entry<String, SpringValue> springValue = springValueIterator.next();
68+
if (!springValue.getValue().isTargetBeanValid()) {
69+
// clear unused spring values
70+
springValueIterator.remove();
71+
}
72+
}
73+
}
74+
}
3475
}

0 commit comments

Comments
 (0)