Skip to content

Fix memory leak in MHistorConfig & MBeanExpHelper #2531

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionValidationException;
import org.springframework.context.SmartLifecycle;
import org.springframework.integration.support.management.IntegrationManagedResource;
Expand All @@ -50,13 +50,13 @@
*/
@ManagedResource
@IntegrationManagedResource
public class MessageHistoryConfigurer implements SmartLifecycle, BeanFactoryAware, BeanPostProcessor {
public class MessageHistoryConfigurer implements SmartLifecycle, BeanFactoryAware, DestructionAwareBeanPostProcessor {

private final Log logger = LogFactory.getLog(this.getClass());

private final Set<TrackableComponent> currentlyTrackedComponents = ConcurrentHashMap.newKeySet();

private String[] componentNamePatterns = new String[] { "*" };
private String[] componentNamePatterns = new String[]{ "*" };

private boolean componentNamePatternsExplicitlySet;

Expand Down Expand Up @@ -98,7 +98,7 @@ public void setComponentNamePatterns(String[] componentNamePatterns) {
*/
@ManagedAttribute(description = "comma-delimited list of patterns; must invoke stop() before changing.")
public void setComponentNamePatternsString(String componentNamePatterns) {
this.setComponentNamePatterns(StringUtils.delimitedListToStringArray(componentNamePatterns, ",", " "));
setComponentNamePatterns(StringUtils.delimitedListToStringArray(componentNamePatterns, ",", " "));
}

@ManagedAttribute
Expand Down Expand Up @@ -160,6 +160,16 @@ private void trackComponentIfAny(TrackableComponent component) {
}
}

@Override
public boolean requiresDestruction(Object bean) {
return bean instanceof TrackableComponent;
}

@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
this.currentlyTrackedComponents.remove(bean);
}

/*
* SmartLifecycle implementation
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,16 +16,17 @@

package org.springframework.integration.jmx.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Consumer;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.integration.monitor.IntegrationMBeanExporter;
Expand All @@ -40,28 +41,29 @@
*
* @author Oleg Zhurakousky
* @author Artem Bilan
*
* @since 2.1
*
*/
class MBeanExporterHelper implements BeanPostProcessor, Ordered {
class MBeanExporterHelper implements DestructionAwareBeanPostProcessor, Ordered {

private final List<MBeanExporter> mBeanExportersForExcludes = new ArrayList<MBeanExporter>();
private final Queue<MBeanExporter> mBeanExportersForExcludes = new ConcurrentLinkedQueue<>();

private final Set<String> siBeanNames = new HashSet<String>();
private final Set<String> siBeanNames = ConcurrentHashMap.newKeySet();

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("$autoCreateChannelCandidates".equals(beanName)) {
@SuppressWarnings("unchecked")
Collection<String> autoCreateChannelCandidatesNames = (Collection<String>) new DirectFieldAccessor(bean)
.getPropertyValue("channelNames");
Collection<String> autoCreateChannelCandidatesNames =
(Collection<String>) new DirectFieldAccessor(bean).getPropertyValue("channelNames");
this.siBeanNames.addAll(autoCreateChannelCandidatesNames);
if (!this.mBeanExportersForExcludes.isEmpty()) {
for (String autoCreateChannelCandidatesName : autoCreateChannelCandidatesNames) {
for (MBeanExporter mBeanExporter : this.mBeanExportersForExcludes) {
mBeanExporter.addExcludedBean(autoCreateChannelCandidatesName);
}
}
autoCreateChannelCandidatesNames
.stream().
<Consumer<? super MBeanExporter>>map(candidateName ->
mBeanExporter -> mBeanExporter.addExcludedBean(candidateName))
.forEach(this.mBeanExportersForExcludes::forEach);
}
}

Expand All @@ -72,25 +74,37 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (AnnotatedElementUtils.isAnnotated(AopUtils.getTargetClass(bean),
IntegrationManagedResource.class.getName())) {

this.siBeanNames.add(beanName);
if (!this.mBeanExportersForExcludes.isEmpty()) {
for (MBeanExporter mBeanExporter : this.mBeanExportersForExcludes) {
mBeanExporter.addExcludedBean(beanName);
}
}
this.mBeanExportersForExcludes.forEach(mBeanExporter -> mBeanExporter.addExcludedBean(beanName));
}

if (bean instanceof MBeanExporter && !(bean instanceof IntegrationMBeanExporter)) {
MBeanExporter mBeanExporter = (MBeanExporter) bean;
this.mBeanExportersForExcludes.add(mBeanExporter);
for (String siBeanName : this.siBeanNames) {
mBeanExporter.addExcludedBean(siBeanName);
}
this.siBeanNames.forEach(mBeanExporter::addExcludedBean);
}

return bean;
}

@Override
public boolean requiresDestruction(Object bean) {
return (bean instanceof MBeanExporter && !(bean instanceof IntegrationMBeanExporter)) ||
AnnotatedElementUtils.isAnnotated(AopUtils.getTargetClass(bean),
IntegrationManagedResource.class.getName());
}

@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (bean instanceof MBeanExporter) {
this.mBeanExportersForExcludes.remove(bean);
}
else {
this.siBeanNames.remove(beanName);
}
}

@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
Expand Down