Dispose default Scheduler
AbstractUserDetailsReactiveAuthenticationManager creates parallel Scheduler with daemon=false Threads. It is recommended to dispose such Schedulers to be able exit the VM Fixes gh-7492
This commit is contained in:
		
							parent
							
								
									29ed728a70
								
							
						
					
					
						commit
						39600b901f
					
				| 
						 | 
					@ -18,6 +18,7 @@ package org.springframework.security.authentication;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.apache.commons.logging.Log;
 | 
					import org.apache.commons.logging.Log;
 | 
				
			||||||
import org.apache.commons.logging.LogFactory;
 | 
					import org.apache.commons.logging.LogFactory;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.DisposableBean;
 | 
				
			||||||
import reactor.core.publisher.Mono;
 | 
					import reactor.core.publisher.Mono;
 | 
				
			||||||
import reactor.core.scheduler.Scheduler;
 | 
					import reactor.core.scheduler.Scheduler;
 | 
				
			||||||
import reactor.core.scheduler.Schedulers;
 | 
					import reactor.core.scheduler.Schedulers;
 | 
				
			||||||
| 
						 | 
					@ -45,7 +46,7 @@ import org.springframework.util.Assert;
 | 
				
			||||||
 * @author Eddú Meléndez
 | 
					 * @author Eddú Meléndez
 | 
				
			||||||
 * @since 5.2
 | 
					 * @since 5.2
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class AbstractUserDetailsReactiveAuthenticationManager implements ReactiveAuthenticationManager {
 | 
					public abstract class AbstractUserDetailsReactiveAuthenticationManager implements ReactiveAuthenticationManager, DisposableBean {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected final Log logger = LogFactory.getLog(getClass());
 | 
						protected final Log logger = LogFactory.getLog(getClass());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,7 +56,8 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private ReactiveUserDetailsPasswordService userDetailsPasswordService;
 | 
						private ReactiveUserDetailsPasswordService userDetailsPasswordService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private Scheduler scheduler = Schedulers.newParallel("password-encoder");
 | 
						Scheduler scheduler = Schedulers.newParallel("password-encoder");
 | 
				
			||||||
 | 
						private boolean defaultScheduler = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private UserDetailsChecker preAuthenticationChecks = user -> {
 | 
						private UserDetailsChecker preAuthenticationChecks = user -> {
 | 
				
			||||||
		if (!user.isAccountNonLocked()) {
 | 
							if (!user.isAccountNonLocked()) {
 | 
				
			||||||
| 
						 | 
					@ -138,6 +140,10 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void setScheduler(Scheduler scheduler) {
 | 
						public void setScheduler(Scheduler scheduler) {
 | 
				
			||||||
		Assert.notNull(scheduler, "scheduler cannot be null");
 | 
							Assert.notNull(scheduler, "scheduler cannot be null");
 | 
				
			||||||
 | 
							if (this.defaultScheduler) {
 | 
				
			||||||
 | 
								this.defaultScheduler = false;
 | 
				
			||||||
 | 
								this.scheduler.dispose();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		this.scheduler = scheduler;
 | 
							this.scheduler = scheduler;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,4 +177,10 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected abstract Mono<UserDetails> retrieveUser(String username);
 | 
						protected abstract Mono<UserDetails> retrieveUser(String username);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public void destroy() {
 | 
				
			||||||
 | 
							if (this.defaultScheduler) {
 | 
				
			||||||
 | 
								this.scheduler.dispose();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,8 @@ import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
 | 
				
			||||||
import org.springframework.security.core.userdetails.UserDetails;
 | 
					import org.springframework.security.core.userdetails.UserDetails;
 | 
				
			||||||
import org.springframework.security.crypto.password.PasswordEncoder;
 | 
					import org.springframework.security.crypto.password.PasswordEncoder;
 | 
				
			||||||
import reactor.core.publisher.Mono;
 | 
					import reactor.core.publisher.Mono;
 | 
				
			||||||
 | 
					import reactor.core.scheduler.Scheduler;
 | 
				
			||||||
 | 
					import reactor.core.scheduler.Schedulers;
 | 
				
			||||||
import reactor.test.StepVerifier;
 | 
					import reactor.test.StepVerifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -136,4 +138,33 @@ public class ReactiveUserDetailsServiceAuthenticationManagerTests {
 | 
				
			||||||
			.expectError(BadCredentialsException.class)
 | 
								.expectError(BadCredentialsException.class)
 | 
				
			||||||
			.verify();
 | 
								.verify();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void destroyWhenDefaultSchedulerThenShouldDispose() {
 | 
				
			||||||
 | 
							assertThat(manager.scheduler.isDisposed()).isFalse();
 | 
				
			||||||
 | 
							manager.destroy();
 | 
				
			||||||
 | 
							assertThat(manager.scheduler.isDisposed())
 | 
				
			||||||
 | 
									.as("default Scheduler should be disposed")
 | 
				
			||||||
 | 
									.isTrue();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void destroyWhenCustomSchedulerThenShouldNotDispose() {
 | 
				
			||||||
 | 
							manager.setScheduler(Schedulers.parallel());
 | 
				
			||||||
 | 
							manager.destroy();
 | 
				
			||||||
 | 
							assertThat(manager.scheduler.isDisposed())
 | 
				
			||||||
 | 
									.as("custom Scheduler should not be disposed")
 | 
				
			||||||
 | 
									.isFalse();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void setSchedulerWhenSetCustomSchedulerThenDisposeDefault() {
 | 
				
			||||||
 | 
							Scheduler defaultScheduler = manager.scheduler;
 | 
				
			||||||
 | 
							assertThat(defaultScheduler.isDisposed()).isFalse();
 | 
				
			||||||
 | 
							manager.setScheduler(Schedulers.parallel());
 | 
				
			||||||
 | 
							assertThat(defaultScheduler.isDisposed())
 | 
				
			||||||
 | 
									.as("default Scheduler should be disposed")
 | 
				
			||||||
 | 
									.isTrue();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue