1 16 17 package org.springframework.beans.factory.support; 18 19 import java.io.Serializable ; 20 import java.lang.reflect.InvocationTargetException ; 21 import java.lang.reflect.Method ; 22 import java.lang.reflect.Modifier ; 23 import java.util.ArrayList ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 27 import org.apache.commons.logging.Log; 28 import org.apache.commons.logging.LogFactory; 29 30 import org.springframework.beans.BeanUtils; 31 import org.springframework.beans.factory.DisposableBean; 32 import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; 33 import org.springframework.util.Assert; 34 35 51 class DisposableBeanAdapter implements DisposableBean, Runnable , Serializable { 52 53 private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class); 54 55 private final Object bean; 56 57 private final String beanName; 58 59 private final String destroyMethodName; 60 61 private final boolean enforceDestroyMethod; 62 63 private List beanPostProcessors; 64 65 66 74 public DisposableBeanAdapter( 75 Object bean, String beanName, RootBeanDefinition beanDefinition, List postProcessors) { 76 77 Assert.notNull(bean, "Bean must not be null"); 78 this.bean = bean; 79 this.beanName = beanName; 80 this.destroyMethodName = beanDefinition.getDestroyMethodName(); 81 this.enforceDestroyMethod = beanDefinition.isEnforceDestroyMethod(); 82 this.beanPostProcessors = filterPostProcessors(postProcessors); 83 } 84 85 95 private DisposableBeanAdapter( 96 Object bean, String beanName, String destroyMethodName, boolean enforceDestroyMethod, List postProcessors) { 97 98 this.bean = bean; 99 this.beanName = beanName; 100 this.destroyMethodName = destroyMethodName; 101 this.enforceDestroyMethod = enforceDestroyMethod; 102 this.beanPostProcessors = postProcessors; 103 } 104 105 110 private List filterPostProcessors(List postProcessors) { 111 List filteredPostProcessors = null; 112 if (postProcessors != null && !postProcessors.isEmpty()) { 113 filteredPostProcessors = new ArrayList (postProcessors.size()); 114 for (Iterator it = postProcessors.iterator(); it.hasNext();) { 115 Object postProcessor = it.next(); 116 if (postProcessor instanceof DestructionAwareBeanPostProcessor) { 117 filteredPostProcessors.add(postProcessor); 118 } 119 } 120 } 121 return filteredPostProcessors; 122 } 123 124 125 public void run() { 126 destroy(); 127 } 128 129 public void destroy() { 130 if (this.beanPostProcessors != null && !this.beanPostProcessors.isEmpty()) { 131 if (logger.isTraceEnabled()) { 132 logger.trace("Applying DestructionAwareBeanPostProcessors to bean with name '" + this.beanName + "'"); 133 } 134 for (int i = this.beanPostProcessors.size() - 1; i >= 0; i--) { 135 ((DestructionAwareBeanPostProcessor) this.beanPostProcessors.get(i)).postProcessBeforeDestruction( 136 this.bean, this.beanName); 137 } 138 } 139 140 if (this.bean instanceof DisposableBean) { 141 if (logger.isDebugEnabled()) { 142 logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'"); 143 } 144 try { 145 ((DisposableBean) this.bean).destroy(); 146 } 147 catch (Throwable ex) { 148 logger.error("Couldn't invoke destroy method of bean with name '" + this.beanName + "'", ex); 149 } 150 } 151 152 if (this.destroyMethodName != null) { 153 invokeCustomDestroyMethod(); 154 } 155 } 156 157 163 private void invokeCustomDestroyMethod() { 164 if (this.destroyMethodName != null) { 165 try { 166 Method destroyMethod = BeanUtils.findMethodWithMinimalParameters(this.bean.getClass(), destroyMethodName); 167 if (destroyMethod == null) { 168 if (this.enforceDestroyMethod) { 169 logger.error("Couldn't find a destroy method named '" + destroyMethodName + 170 "' on bean with name '" + this.beanName + "'"); 171 } 172 } 173 174 else { 175 Class [] paramTypes = destroyMethod.getParameterTypes(); 176 if (paramTypes.length > 1) { 177 logger.error("Method '" + destroyMethodName + "' of bean '" + this.beanName + 178 "' has more than one parameter - not supported as destroy method"); 179 } 180 else if (paramTypes.length == 1 && !paramTypes[0].equals(boolean.class)) { 181 logger.error("Method '" + destroyMethodName + "' of bean '" + this.beanName + 182 "' has a non-boolean parameter - not supported as destroy method"); 183 } 184 185 else { 186 Object [] args = new Object [paramTypes.length]; 187 if (paramTypes.length == 1) { 188 args[0] = Boolean.TRUE; 189 } 190 if (!Modifier.isPublic(destroyMethod.getModifiers()) || 191 !Modifier.isPublic(destroyMethod.getDeclaringClass().getModifiers())) { 192 destroyMethod.setAccessible(true); 193 } 194 195 if (logger.isDebugEnabled()) { 196 logger.debug("Invoking custom destroy method on bean with name '" + this.beanName + "'"); 197 } 198 try { 199 destroyMethod.invoke(this.bean, args); 200 } 201 catch (InvocationTargetException ex) { 202 logger.error("Couldn't invoke destroy method '" + destroyMethodName + 203 "' of bean with name '" + this.beanName + "'", ex.getTargetException()); 204 } 205 catch (Throwable ex) { 206 logger.error("Couldn't invoke destroy method '" + destroyMethodName + 207 "' of bean with name '" + this.beanName + "'", ex); 208 } 209 } 210 } 211 } 212 catch (IllegalArgumentException ex) { 213 logger.error("Couldn't find a unique destroy method on bean with name '" + 215 this.beanName + ": " + ex.getMessage()); 216 } 217 } 218 } 219 220 221 225 protected Object writeReplace() { 226 List serializablePostProcessors = null; 227 if (this.beanPostProcessors != null) { 228 serializablePostProcessors = new ArrayList (); 229 for (Iterator it = this.beanPostProcessors.iterator(); it.hasNext();) { 230 Object postProcessor = it.next(); 231 if (postProcessor instanceof Serializable ) { 232 serializablePostProcessors.add(postProcessor); 233 } 234 } 235 } 236 return new DisposableBeanAdapter(this.bean, this.beanName, this.destroyMethodName, 237 this.enforceDestroyMethod, serializablePostProcessors); 238 } 239 240 } 241 | Popular Tags |