/** * Constructs a new <code>ManagedFactoryDisposableAdapter</code> instance. * * @param methodName destruction method name */ public ManagedFactoryDisposableInvoker(Class<?> beanClass, String methodName) { this.isDisposable = DisposableBean.class.isAssignableFrom(beanClass); if (StringUtils.hasText(methodName)) { this.customSpringMethod = detectCustomSpringMethod(beanClass, methodName); if (customSpringMethod != null) { Class<?>[] types = customSpringMethod.getParameterTypes(); this.customSpringMethodArgs = ((types.length == 1 && types[0].equals(boolean.class)) ? new Object[] { Boolean.TRUE } : null); } else { this.customSpringMethodArgs = null; } this.customOsgiDestructionMethod = detectCustomOsgiMethod(beanClass, methodName); } else { this.customSpringMethod = null; this.customSpringMethodArgs = null; this.customOsgiDestructionMethod = null; } }
public void destroy(String beanName, Object beanInstance, DestructionCodes code) { // first invoke disposable bean if (isDisposable) { if (log.isDebugEnabled()) { log.debug("Invoking destroy() on bean with name '" + beanName + "'"); } try { ((DisposableBean) beanInstance).destroy(); } catch (Throwable ex) { String msg = "Invocation of destroy method failed on bean with name '" + beanName + "'"; if (log.isDebugEnabled()) { log.warn(msg, ex); } else { log.warn(msg + ": " + ex); } } } // custom callback (no argument) invokeCustomMethod(beanName, beanInstance); // custom callback (int argument) invokeCustomMethod(beanName, beanInstance, code); }
public void testAppContextClassHierarchy() { Class<?>[] clazz = ClassUtils.getClassHierarchy(OsgiBundleXmlApplicationContext.class, ClassUtils.ClassSet.ALL_CLASSES); //Closeable.class, Class<?>[] expected = new Class<?>[] { OsgiBundleXmlApplicationContext.class, AbstractDelegatedExecutionApplicationContext.class, AbstractOsgiBundleApplicationContext.class, AbstractRefreshableApplicationContext.class, AbstractApplicationContext.class, DefaultResourceLoader.class, ResourceLoader.class, AutoCloseable.class, DelegatedExecutionOsgiBundleApplicationContext.class, ConfigurableOsgiBundleApplicationContext.class, ConfigurableApplicationContext.class, ApplicationContext.class, Lifecycle.class, Closeable.class, EnvironmentCapable.class, ListableBeanFactory.class, HierarchicalBeanFactory.class, ApplicationEventPublisher.class, ResourcePatternResolver.class, MessageSource.class, BeanFactory.class, DisposableBean.class }; assertTrue(compareArrays(expected, clazz)); }
/** * Find all ServletContext attributes which implement {@link DisposableBean} * and destroy them, removing all affected ServletContext attributes eventually. * @param sc the ServletContext to check */ static void cleanupAttributes(ServletContext sc) { Enumeration<String> attrNames = sc.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = attrNames.nextElement(); if (attrName.startsWith("org.springframework.")) { Object attrValue = sc.getAttribute(attrName); if (attrValue instanceof DisposableBean) { try { ((DisposableBean) attrValue).destroy(); } catch (Throwable ex) { logger.error("Couldn't invoke destroy method of attribute with name '" + attrName + "'", ex); } } } } }
/** * If the current value of the given beanDefinition's "destroyMethodName" property is * {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method. * Candidate methods are currently limited to public, no-arg methods named "close" * (whether declared locally or inherited). The given BeanDefinition's * "destroyMethodName" is updated to be null if no such method is found, otherwise set * to the name of the inferred method. This constant serves as the default for the * {@code @Bean#destroyMethod} attribute and the value of the constant may also be * used in XML within the {@code <bean destroy-method="">} or {@code * <beans default-destroy-method="">} attributes. * <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable} * interfaces, reflectively calling the "close" method on implementing beans as well. */ private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) { if (AbstractBeanDefinition.INFER_METHOD.equals(beanDefinition.getDestroyMethodName()) || (beanDefinition.getDestroyMethodName() == null && closeableInterface.isInstance(bean))) { // Only perform destroy method inference or Closeable detection // in case of the bean not explicitly implementing DisposableBean if (!(bean instanceof DisposableBean)) { try { return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName(); } catch (NoSuchMethodException ex) { try { return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName(); } catch (NoSuchMethodException ex2) { // no candidate destroy method found } } } return null; } return beanDefinition.getDestroyMethodName(); }
/** * Subclasses should call this method to destroy an obsolete prototype instance. * @param target the bean instance to destroy */ protected void destroyPrototypeInstance(Object target) { if (this.logger.isDebugEnabled()) { this.logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'"); } if (getBeanFactory() instanceof ConfigurableBeanFactory) { ((ConfigurableBeanFactory) getBeanFactory()).destroyBean(getTargetBeanName(), target); } else if (target instanceof DisposableBean) { try { ((DisposableBean) target).destroy(); } catch (Throwable ex) { logger.error("Couldn't invoke destroy method of bean with name '" + getTargetBeanName() + "'", ex); } } }
/** * If the current value of the given beanDefinition's "destroyMethodName" property is * {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method. * Candidate methods are currently limited to public, no-arg methods named "close" or * "shutdown" (whether declared locally or inherited). The given BeanDefinition's * "destroyMethodName" is updated to be null if no such method is found, otherwise set * to the name of the inferred method. This constant serves as the default for the * {@code @Bean#destroyMethod} attribute and the value of the constant may also be * used in XML within the {@code <bean destroy-method="">} or {@code * <beans default-destroy-method="">} attributes. * <p>Also processes the {@link java.io.Closeable} and {@link java.lang.AutoCloseable} * interfaces, reflectively calling the "close" method on implementing beans as well. */ private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) { String destroyMethodName = beanDefinition.getDestroyMethodName(); if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) || (destroyMethodName == null && closeableInterface.isInstance(bean))) { // Only perform destroy method inference or Closeable detection // in case of the bean not explicitly implementing DisposableBean if (!(bean instanceof DisposableBean)) { try { return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName(); } catch (NoSuchMethodException ex) { try { return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName(); } catch (NoSuchMethodException ex2) { // no candidate destroy method found } } } return null; } return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null); }
/** * Close the root web application context. */ @Override public void contextDestroyed(ServletContextEvent event) { DisambiguationMainService.getInstance().shutDownDisambiguationService(); if (this.contextLoader != null) { this.contextLoader.closeWebApplicationContext(event .getServletContext()); } ServletContext sc = event.getServletContext(); Enumeration<String> attrNames = sc.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = attrNames.nextElement(); if (attrName.startsWith("org.springframework.")) { Object attrValue = sc.getAttribute(attrName); if (attrValue instanceof DisposableBean) { try { ((DisposableBean) attrValue).destroy(); } catch (Throwable ex) { Logger.getRootLogger().fatal(ex.getMessage()); } } } } }
/** * Tries to "close" an object. * <p> * This invokes the close method if it is present. * * @param obj the object, null ignored */ public static void close(final Object obj) { if (obj != null) { try { if (obj instanceof Closeable) { ((Closeable) obj).close(); } else if (obj instanceof Lifecycle) { ((Lifecycle) obj).stop(); } else if (obj instanceof DisposableBean) { ((DisposableBean) obj).destroy(); } else { invokeNoArgsNoException(obj, "close"); invokeNoArgsNoException(obj, "stop"); invokeNoArgsNoException(obj, "shutdown"); } } catch (Exception ex) { // ignored } } }
/** * If an AsyncTaskExecutor is used for loading options/services/transforms, we need to wait for the tasks to complete * before we e.g. release the DatabaseClient. */ public void waitForTaskExecutorToFinish() { if (shutdownTaskExecutorAfterLoadingModules) { if (taskExecutor instanceof ExecutorConfigurationSupport) { ((ExecutorConfigurationSupport) taskExecutor).shutdown(); taskExecutor = null; } else if (taskExecutor instanceof DisposableBean) { try { ((DisposableBean) taskExecutor).destroy(); } catch (Exception ex) { logger.warn("Unexpected exception while calling destroy() on taskExecutor: " + ex.getMessage(), ex); } taskExecutor = null; } } else if (logger.isDebugEnabled()) { logger.debug("shutdownTaskExecutorAfterLoadingModules is set to false, so not shutting down taskExecutor"); } }
/** */ protected void onTearDown() throws Exception { if (this.HotBeanModuleRepository1 instanceof AbstractHotBeanModuleRepository) ((AbstractHotBeanModuleRepository) this.HotBeanModuleRepository1) .destroy(); else if (this.HotBeanModuleRepository1 instanceof DisposableBean) ((DisposableBean) this.HotBeanModuleRepository1).destroy(); if (this.HotBeanModuleRepository2 instanceof AbstractHotBeanModuleRepository) ((AbstractHotBeanModuleRepository) this.HotBeanModuleRepository2) .destroy(); else if (this.HotBeanModuleRepository2 instanceof DisposableBean) ((DisposableBean) this.HotBeanModuleRepository2).destroy(); logger.info("Cleaning up files."); // Clean up // FileDeletor.deleteTreeImpl("test/junit/hotModules"); logger.info("Clean up complete."); }
/** * Find all ServletContext attributes which implement {@link DisposableBean} * and destroy them, removing all affected ServletContext attributes eventually. * @param sc the ServletContext to check */ static void cleanupAttributes(ServletContext sc) { Enumeration attrNames = sc.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (attrName.startsWith("org.springframework.")) { Object attrValue = sc.getAttribute(attrName); if (attrValue instanceof DisposableBean) { try { ((DisposableBean) attrValue).destroy(); } catch (Throwable ex) { logger.error("Couldn't invoke destroy method of attribute with name '" + attrName + "'", ex); } } } } }
@Test public void createCache_withMockedRedisConnectionFactory_createsAndDestroysConnectionFactory() throws Exception { //Arrange RedisConnectionFactory connectionFactory = Mockito.mock(RedisConnectionFactory.class, Mockito.withSettings().extraInterfaces(DisposableBean.class)); RedisCacheFactory redisCacheFactory = new RedisCacheFactory() { @Override protected RedisConnectionFactory createConnectionClient(String hostName, int port) { assertEquals("someHost", hostName); assertEquals(4711, port); return connectionFactory; } }; //Act Cache cache = redisCacheFactory.createCache("test", "someHost", 4711); redisCacheFactory.destroy(); //Assert assertNotNull(cache); assertEquals("test", cache.getName()); assertNotNull(cache.getNativeCache()); DisposableBean disposableBean = (DisposableBean) connectionFactory; Mockito.verify(disposableBean, Mockito.times(1)).destroy(); }
public void testAppContextClassHierarchy() { Class[] clazz = ClassUtils.getClassHierarchy(OsgiBundleXmlApplicationContext.class, ClassUtils.INCLUDE_ALL_CLASSES); Class[] expected = new Class[] { OsgiBundleXmlApplicationContext.class, AbstractDelegatedExecutionApplicationContext.class, DelegatedExecutionOsgiBundleApplicationContext.class, ConfigurableOsgiBundleApplicationContext.class, ConfigurableApplicationContext.class, ApplicationContext.class, Lifecycle.class, Closeable.class, EnvironmentCapable.class, ListableBeanFactory.class, HierarchicalBeanFactory.class, MessageSource.class, ApplicationEventPublisher.class, ResourcePatternResolver.class, BeanFactory.class, ResourceLoader.class, AutoCloseable.class, AbstractOsgiBundleApplicationContext.class, AbstractRefreshableApplicationContext.class, AbstractApplicationContext.class, DisposableBean.class, DefaultResourceLoader.class }; String msg = "Class: "; for (int i=0;i<clazz.length;i++) { msg += clazz[i].getSimpleName() + " "; } assertTrue(msg, compareArrays(expected, clazz)); }
@Override public void destroy() throws Exception { if (executor instanceof DisposableBean) { DisposableBean bean = (DisposableBean) executor; bean.destroy(); } }
@Override public void destroy() throws Exception { if (dedicatedSessionManager && sessionManager instanceof DisposableBean) { ((DisposableBean) sessionManager).destroy(); } }
/** * {@inheritDoc} * * Cleanup the configuration items. */ public void stop(BundleContext extenderBundleContext) { synchronized (lock) { if (isMulticasterManagedInternally) { eventMulticaster.removeAllListeners(); eventMulticaster = null; } if (extenderConfiguration != null) { extenderConfiguration.close(); extenderConfiguration = null; } // postpone the task executor shutdown if (forceThreadShutdown) { if (isTaskExecutorManagedInternally) { log.warn("Forcing the (internally created) taskExecutor to stop..."); ThreadGroup th = ((ThreadPoolTaskExecutor) taskExecutor).getThreadGroup(); if (!th.isDestroyed()) { // ask the threads nicely to stop th.interrupt(); } } taskExecutor = null; } if (isShutdownTaskExecutorManagedInternally) { try { ((DisposableBean) shutdownTaskExecutor).destroy(); } catch (Exception ex) { log.debug("Received exception while shutting down shutdown task executor", ex); } shutdownTaskExecutor = null; } } }
public static boolean execute(Runnable task, long waitTime, TaskExecutor taskExecutor) { Assert.notNull(task); Counter counter = new Counter("counter for task: " + task); Runnable wrapper = new MonitoredRunnable(task, counter); boolean internallyManaged = false; if (taskExecutor == null) { taskExecutor = new SimpleTaskExecutor(); internallyManaged = true; } counter.increment(); taskExecutor.execute(wrapper); if (counter.waitForZero(waitTime)) { log.error(task + " did not finish in " + waitTime + "ms; consider taking a snapshot and then shutdown the VM in case the thread still hangs"); //log.error("Current Thread dump***\n" + ThreadDump.dumpThreads()); if (internallyManaged) { try { ((DisposableBean) taskExecutor).destroy(); } catch (Exception e) { log.error("Exception thrown while destroying internally managed thread executor", e); } } return true; } return false; }
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { Enhancer.registerStaticCallbacks(obj.getClass(), null); // Does the actual (non-CGLIB) superclass actually implement DisposableBean? // If so, call its dispose() method. If not, just exit. if (DisposableBean.class.isAssignableFrom(obj.getClass().getSuperclass())) { return proxy.invokeSuper(obj, args); } return null; }
/** * Create a new DisposableBeanAdapter for the given bean. * @param bean the bean instance (never {@code null}) * @param beanName the name of the bean * @param beanDefinition the merged bean definition * @param postProcessors the List of BeanPostProcessors * (potentially DestructionAwareBeanPostProcessor), if any */ public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition, List<BeanPostProcessor> postProcessors, AccessControlContext acc) { Assert.notNull(bean, "Disposable bean must not be null"); this.bean = bean; this.beanName = beanName; this.invokeDisposableBean = (this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy")); this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed(); this.acc = acc; String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition); if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) && !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { this.destroyMethodName = destroyMethodName; this.destroyMethod = determineDestroyMethod(); if (this.destroyMethod == null) { if (beanDefinition.isEnforceDestroyMethod()) { throw new BeanDefinitionValidationException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'"); } } else { Class<?>[] paramTypes = this.destroyMethod.getParameterTypes(); if (paramTypes.length > 1) { throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" + beanName + "' has more than one parameter - not supported as destroy method"); } else if (paramTypes.length == 1 && !paramTypes[0].equals(boolean.class)) { throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" + beanName + "' has a non-boolean parameter - not supported as destroy method"); } } } this.beanPostProcessors = filterPostProcessors(postProcessors); }
/** * Create a new DisposableBeanAdapter for the given bean. * @param bean the bean instance (never {@code null}) * @param postProcessors the List of BeanPostProcessors * (potentially DestructionAwareBeanPostProcessor), if any */ public DisposableBeanAdapter(Object bean, List<BeanPostProcessor> postProcessors, AccessControlContext acc) { Assert.notNull(bean, "Disposable bean must not be null"); this.bean = bean; this.beanName = null; this.invokeDisposableBean = (this.bean instanceof DisposableBean); this.nonPublicAccessAllowed = true; this.acc = acc; this.beanPostProcessors = filterPostProcessors(postProcessors); }
/** * Check whether the given bean has any kind of destroy method to call. * @param bean the bean instance * @param beanDefinition the corresponding bean definition */ public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) { if (bean instanceof DisposableBean || closeableInterface.isInstance(bean)) { return true; } String destroyMethodName = beanDefinition.getDestroyMethodName(); if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) { return ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME); } return (destroyMethodName != null); }
protected void dispose(String name, Object bean) { if (DisposableBean.class.isInstance(bean)) { DisposableBean disposable = DisposableBean.class.cast(bean); try { disposable.destroy(); } catch (Exception e) { logger.warn("unable to dispose of bean {}", name, bean); } } }
@Test public void okHttp3ClientCreated() throws Exception { ClientHttpRequestFactory factory = usingOkHttp3(new ClientOptions()); assertThat(factory, instanceOf(OkHttp3ClientHttpRequestFactory.class)); ((DisposableBean) factory).destroy(); }
@Test public void nettyClientCreated() throws Exception { ClientHttpRequestFactory factory = usingNetty(new ClientOptions()); assertThat(factory, instanceOf(Netty4ClientHttpRequestFactory.class)); ((DisposableBean) factory).destroy(); }
@Override public void destroy() { for (MessageListenerContainer listenerContainer : getListenerContainers()) { if (listenerContainer instanceof DisposableBean) { try { ((DisposableBean) listenerContainer).destroy(); } catch (Throwable ex) { logger.warn("Failed to destroy message listener container", ex); } } } }