001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.scheduling.config; 018 019import java.util.concurrent.RejectedExecutionHandler; 020 021import org.springframework.beans.factory.BeanNameAware; 022import org.springframework.beans.factory.DisposableBean; 023import org.springframework.beans.factory.FactoryBean; 024import org.springframework.beans.factory.InitializingBean; 025import org.springframework.core.task.TaskExecutor; 026import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 027import org.springframework.util.StringUtils; 028 029/** 030 * {@link FactoryBean} for creating {@link ThreadPoolTaskExecutor} instances, 031 * primarily used behind the XML task namespace. 032 * 033 * @author Mark Fisher 034 * @author Juergen Hoeller 035 * @since 3.0 036 */ 037public class TaskExecutorFactoryBean implements 038 FactoryBean<TaskExecutor>, BeanNameAware, InitializingBean, DisposableBean { 039 040 private String poolSize; 041 042 private Integer queueCapacity; 043 044 private RejectedExecutionHandler rejectedExecutionHandler; 045 046 private Integer keepAliveSeconds; 047 048 private String beanName; 049 050 private ThreadPoolTaskExecutor target; 051 052 053 public void setPoolSize(String poolSize) { 054 this.poolSize = poolSize; 055 } 056 057 public void setQueueCapacity(int queueCapacity) { 058 this.queueCapacity = queueCapacity; 059 } 060 061 public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) { 062 this.rejectedExecutionHandler = rejectedExecutionHandler; 063 } 064 065 public void setKeepAliveSeconds(int keepAliveSeconds) { 066 this.keepAliveSeconds = keepAliveSeconds; 067 } 068 069 @Override 070 public void setBeanName(String beanName) { 071 this.beanName = beanName; 072 } 073 074 075 @Override 076 public void afterPropertiesSet() { 077 this.target = new ThreadPoolTaskExecutor(); 078 determinePoolSizeRange(); 079 if (this.queueCapacity != null) { 080 this.target.setQueueCapacity(this.queueCapacity); 081 } 082 if (this.keepAliveSeconds != null) { 083 this.target.setKeepAliveSeconds(this.keepAliveSeconds); 084 } 085 if (this.rejectedExecutionHandler != null) { 086 this.target.setRejectedExecutionHandler(this.rejectedExecutionHandler); 087 } 088 if (this.beanName != null) { 089 this.target.setThreadNamePrefix(this.beanName + "-"); 090 } 091 this.target.afterPropertiesSet(); 092 } 093 094 private void determinePoolSizeRange() { 095 if (StringUtils.hasText(this.poolSize)) { 096 try { 097 int corePoolSize; 098 int maxPoolSize; 099 int separatorIndex = this.poolSize.indexOf('-'); 100 if (separatorIndex != -1) { 101 corePoolSize = Integer.parseInt(this.poolSize.substring(0, separatorIndex)); 102 maxPoolSize = Integer.parseInt(this.poolSize.substring(separatorIndex + 1)); 103 if (corePoolSize > maxPoolSize) { 104 throw new IllegalArgumentException( 105 "Lower bound of pool-size range must not exceed the upper bound"); 106 } 107 if (this.queueCapacity == null) { 108 // No queue-capacity provided, so unbounded 109 if (corePoolSize == 0) { 110 // Actually set 'corePoolSize' to the upper bound of the range 111 // but allow core threads to timeout... 112 this.target.setAllowCoreThreadTimeOut(true); 113 corePoolSize = maxPoolSize; 114 } 115 else { 116 // Non-zero lower bound implies a core-max size range... 117 throw new IllegalArgumentException( 118 "A non-zero lower bound for the size range requires a queue-capacity value"); 119 } 120 } 121 } 122 else { 123 Integer value = Integer.valueOf(this.poolSize); 124 corePoolSize = value; 125 maxPoolSize = value; 126 } 127 this.target.setCorePoolSize(corePoolSize); 128 this.target.setMaxPoolSize(maxPoolSize); 129 } 130 catch (NumberFormatException ex) { 131 throw new IllegalArgumentException("Invalid pool-size value [" + this.poolSize + "]: only single " + 132 "maximum integer (e.g. \"5\") and minimum-maximum range (e.g. \"3-5\") are supported", ex); 133 } 134 } 135 } 136 137 138 @Override 139 public TaskExecutor getObject() { 140 return this.target; 141 } 142 143 @Override 144 public Class<? extends TaskExecutor> getObjectType() { 145 return (this.target != null ? this.target.getClass() : ThreadPoolTaskExecutor.class); 146 } 147 148 @Override 149 public boolean isSingleton() { 150 return true; 151 } 152 153 154 @Override 155 public void destroy() { 156 this.target.destroy(); 157 } 158 159}