From b311088f5a7b2832955bd5894ebd9fa4a47397ce Mon Sep 17 00:00:00 2001 From: Han Li Date: Mon, 24 Apr 2023 22:45:24 +0800 Subject: [PATCH] Optimize DefaultLifecycleProcessor::stopBeans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit optimizes `DefaultLifecycleProcessor::stopBeans` by using a `TreeMap` when gathering the `LifecycleGroup`s during stopBeans. It also switches to a functional style using `computeIfAbsent`. Finally, it further optimizes `LifecycleGroup` by removing sorting of `LifecycleGroupMember` members list entirely, turning the class into a simple record. This is possible because the members list is already comprised of members which all share the same phase value, so sorting according to each member's phase is redundant. Closes gh-30361 Co-authored-by: Simon Baslé --- .../support/DefaultLifecycleProcessor.java | 47 +++++-------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java b/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java index 5c57b1c8651..59bd2ca3e00 100644 --- a/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -18,7 +18,7 @@ package org.springframework.context.support; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; +import java.util.Comparator; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -189,22 +189,16 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor private void stopBeans() { Map lifecycleBeans = getLifecycleBeans(); - Map phases = new HashMap<>(); + Map phases = new TreeMap<>(Comparator.reverseOrder()); lifecycleBeans.forEach((beanName, bean) -> { int shutdownPhase = getPhase(bean); - LifecycleGroup group = phases.get(shutdownPhase); - if (group == null) { - group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false); - phases.put(shutdownPhase, group); - } - group.add(beanName, bean); + phases.computeIfAbsent( + shutdownPhase, + p -> new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false) + ).add(beanName, bean); }); if (!phases.isEmpty()) { - List keys = new ArrayList<>(phases.keySet()); - keys.sort(Collections.reverseOrder()); - for (Integer key : keys) { - phases.get(key).stop(); - } + phases.values().forEach(LifecycleGroup::stop); } } @@ -313,6 +307,8 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor /** * Helper class for maintaining a group of Lifecycle beans that should be started * and stopped together based on their 'phase' value (or the default value of 0). + * The group is expected to be created in an ad-hoc fashion and group members are + * expected to always have the same 'phase' value. */ private class LifecycleGroup { @@ -351,7 +347,6 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor if (logger.isDebugEnabled()) { logger.debug("Starting beans in phase " + this.phase); } - Collections.sort(this.members); for (LifecycleGroupMember member : this.members) { doStart(this.lifecycleBeans, member.name, this.autoStartupOnly); } @@ -364,7 +359,6 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor if (logger.isDebugEnabled()) { logger.debug("Stopping beans in phase " + this.phase); } - this.members.sort(Collections.reverseOrder()); CountDownLatch latch = new CountDownLatch(this.smartMemberCount); Set countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<>()); Set lifecycleBeanNames = new HashSet<>(this.lifecycleBeans.keySet()); @@ -393,25 +387,8 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor /** - * Adapts the Comparable interface onto the lifecycle phase model. + * A simple record of a LifecycleGroup member. */ - private class LifecycleGroupMember implements Comparable { - - private final String name; - - private final Lifecycle bean; - - LifecycleGroupMember(String name, Lifecycle bean) { - this.name = name; - this.bean = bean; - } - - @Override - public int compareTo(LifecycleGroupMember other) { - int thisPhase = getPhase(this.bean); - int otherPhase = getPhase(other.bean); - return Integer.compare(thisPhase, otherPhase); - } - } + private record LifecycleGroupMember(String name, Lifecycle bean) {} }