Skip to content

Commit

Permalink
Merge pull request #1676 from nobodyiam/fix-1670
Browse files Browse the repository at this point in the history
use weak reference to hold bean objects so that they could be garbage collected
  • Loading branch information
nobodyiam authored Nov 17, 2018
2 parents d93a6ba + 790ee89 commit c121a9e
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ctrip.framework.apollo.spring.property;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand All @@ -16,7 +17,7 @@ public class SpringValue {

private MethodParameter methodParameter;
private Field field;
private Object bean;
private WeakReference<Object> beanRef;
private String beanName;
private String key;
private String placeholder;
Expand All @@ -25,7 +26,7 @@ public class SpringValue {
private boolean isJson;

public SpringValue(String key, String placeholder, Object bean, String beanName, Field field, boolean isJson) {
this.bean = bean;
this.beanRef = new WeakReference<>(bean);
this.beanName = beanName;
this.field = field;
this.key = key;
Expand All @@ -38,7 +39,7 @@ public SpringValue(String key, String placeholder, Object bean, String beanName,
}

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

private void injectField(Object newVal) throws IllegalAccessException {
Object bean = beanRef.get();
if (bean == null) {
return;
}
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(bean, newVal);
Expand All @@ -68,6 +73,10 @@ private void injectField(Object newVal) throws IllegalAccessException {

private void injectMethod(Object newVal)
throws InvocationTargetException, IllegalAccessException {
Object bean = beanRef.get();
if (bean == null) {
return;
}
methodParameter.getMethod().invoke(bean, newVal);
}

Expand Down Expand Up @@ -103,8 +112,16 @@ public boolean isJson() {
return isJson;
}

boolean isTargetBeanValid() {
return beanRef.get() != null;
}

@Override
public String toString() {
Object bean = beanRef.get();
if (bean == null) {
return "";
}
if (isField()) {
return String
.format("key: %s, beanName: %s, field: %s.%s", key, beanName, bean.getClass().getName(), field.getName());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
package com.ctrip.framework.apollo.spring.property;

import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.springframework.beans.factory.BeanFactory;

public class SpringValueRegistry {

private static final long CLEAN_INTERVAL_IN_SECONDS = 5;
private final Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap();
private final AtomicBoolean initialized = new AtomicBoolean(false);
private final Object LOCK = new Object();

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

registry.get(beanFactory).put(key, springValue);

// lazy initialize
if (initialized.compareAndSet(false, true)) {
initialize();
}
}

public Collection<SpringValue> get(BeanFactory beanFactory, String key) {
Expand All @@ -31,4 +43,33 @@ public Collection<SpringValue> get(BeanFactory beanFactory, String key) {
}
return beanFactorySpringValues.get(key);
}

private void initialize() {
Executors.newSingleThreadScheduledExecutor(ApolloThreadFactory.create("SpringValueRegistry", true)).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
try {
scanAndClean();
} catch (Throwable ex) {
ex.printStackTrace();
}
}
}, CLEAN_INTERVAL_IN_SECONDS, CLEAN_INTERVAL_IN_SECONDS, TimeUnit.SECONDS);
}

private void scanAndClean() {
Iterator<Multimap<String, SpringValue>> iterator = registry.values().iterator();
while (!Thread.currentThread().isInterrupted() && iterator.hasNext()) {
Multimap<String, SpringValue> springValues = iterator.next();
Iterator<Entry<String, SpringValue>> springValueIterator = springValues.entries().iterator();
while (springValueIterator.hasNext()) {
Entry<String, SpringValue> springValue = springValueIterator.next();
if (!springValue.getValue().isTargetBeanValid()) {
// clear unused spring values
springValueIterator.remove();
}
}
}
}
}

0 comments on commit c121a9e

Please sign in to comment.