Support for registering multiple init/destroy methods on AbstractBeanDefinition
Closes gh-28013
This commit is contained in:
		
							parent
							
								
									8506778608
								
							
						
					
					
						commit
						41ee23345d
					
				|  | @ -74,7 +74,6 @@ import org.springframework.core.ParameterNameDiscoverer; | ||||||
| import org.springframework.core.PriorityOrdered; | import org.springframework.core.PriorityOrdered; | ||||||
| import org.springframework.core.ResolvableType; | import org.springframework.core.ResolvableType; | ||||||
| import org.springframework.lang.Nullable; | import org.springframework.lang.Nullable; | ||||||
| import org.springframework.util.Assert; |  | ||||||
| import org.springframework.util.ClassUtils; | import org.springframework.util.ClassUtils; | ||||||
| import org.springframework.util.ObjectUtils; | import org.springframework.util.ObjectUtils; | ||||||
| import org.springframework.util.ReflectionUtils; | import org.springframework.util.ReflectionUtils; | ||||||
|  | @ -1789,11 +1788,15 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (mbd != null && bean.getClass() != NullBean.class) { | 		if (mbd != null && bean.getClass() != NullBean.class) { | ||||||
| 			String initMethodName = mbd.getInitMethodName(); | 			String[] initMethodNames = mbd.getInitMethodNames(); | ||||||
|  | 			if (initMethodNames != null) { | ||||||
|  | 				for (String initMethodName : initMethodNames) { | ||||||
| 					if (StringUtils.hasLength(initMethodName) && | 					if (StringUtils.hasLength(initMethodName) && | ||||||
| 							!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && | 							!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && | ||||||
| 							!mbd.isExternallyManagedInitMethod(initMethodName)) { | 							!mbd.isExternallyManagedInitMethod(initMethodName)) { | ||||||
| 				invokeCustomInitMethod(beanName, bean, mbd); | 						invokeCustomInitMethod(beanName, bean, mbd, initMethodName); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -1805,11 +1808,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac | ||||||
| 	 * methods with arguments. | 	 * methods with arguments. | ||||||
| 	 * @see #invokeInitMethods | 	 * @see #invokeInitMethods | ||||||
| 	 */ | 	 */ | ||||||
| 	protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd) | 	protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd, String initMethodName) | ||||||
| 			throws Throwable { | 			throws Throwable { | ||||||
| 
 | 
 | ||||||
| 		String initMethodName = mbd.getInitMethodName(); |  | ||||||
| 		Assert.state(initMethodName != null, "No init method set"); |  | ||||||
| 		Method initMethod = (mbd.isNonPublicAccessAllowed() ? | 		Method initMethod = (mbd.isNonPublicAccessAllowed() ? | ||||||
| 				BeanUtils.findMethod(bean.getClass(), initMethodName) : | 				BeanUtils.findMethod(bean.getClass(), initMethodName) : | ||||||
| 				ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName)); | 				ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName)); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2021 the original author or authors. |  * Copyright 2002-2022 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -184,10 +184,10 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess | ||||||
| 	private MethodOverrides methodOverrides = new MethodOverrides(); | 	private MethodOverrides methodOverrides = new MethodOverrides(); | ||||||
| 
 | 
 | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private String initMethodName; | 	private String[] initMethodNames; | ||||||
| 
 | 
 | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private String destroyMethodName; | 	private String[] destroyMethodNames; | ||||||
| 
 | 
 | ||||||
| 	private boolean enforceInitMethod = true; | 	private boolean enforceInitMethod = true; | ||||||
| 
 | 
 | ||||||
|  | @ -262,9 +262,9 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess | ||||||
| 			setInstanceSupplier(originalAbd.getInstanceSupplier()); | 			setInstanceSupplier(originalAbd.getInstanceSupplier()); | ||||||
| 			setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed()); | 			setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed()); | ||||||
| 			setLenientConstructorResolution(originalAbd.isLenientConstructorResolution()); | 			setLenientConstructorResolution(originalAbd.isLenientConstructorResolution()); | ||||||
| 			setInitMethodName(originalAbd.getInitMethodName()); | 			setInitMethodNames(originalAbd.getInitMethodNames()); | ||||||
| 			setEnforceInitMethod(originalAbd.isEnforceInitMethod()); | 			setEnforceInitMethod(originalAbd.isEnforceInitMethod()); | ||||||
| 			setDestroyMethodName(originalAbd.getDestroyMethodName()); | 			setDestroyMethodNames(originalAbd.getDestroyMethodNames()); | ||||||
| 			setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod()); | 			setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod()); | ||||||
| 			setSynthetic(originalAbd.isSynthetic()); | 			setSynthetic(originalAbd.isSynthetic()); | ||||||
| 			setResource(originalAbd.getResource()); | 			setResource(originalAbd.getResource()); | ||||||
|  | @ -338,12 +338,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess | ||||||
| 			setInstanceSupplier(otherAbd.getInstanceSupplier()); | 			setInstanceSupplier(otherAbd.getInstanceSupplier()); | ||||||
| 			setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed()); | 			setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed()); | ||||||
| 			setLenientConstructorResolution(otherAbd.isLenientConstructorResolution()); | 			setLenientConstructorResolution(otherAbd.isLenientConstructorResolution()); | ||||||
| 			if (otherAbd.getInitMethodName() != null) { | 			if (otherAbd.getInitMethodNames() != null) { | ||||||
| 				setInitMethodName(otherAbd.getInitMethodName()); | 				setInitMethodNames(otherAbd.getInitMethodNames()); | ||||||
| 				setEnforceInitMethod(otherAbd.isEnforceInitMethod()); | 				setEnforceInitMethod(otherAbd.isEnforceInitMethod()); | ||||||
| 			} | 			} | ||||||
| 			if (otherAbd.getDestroyMethodName() != null) { | 			if (otherAbd.getDestroyMethodNames() != null) { | ||||||
| 				setDestroyMethodName(otherAbd.getDestroyMethodName()); | 				setDestroyMethodNames(otherAbd.getDestroyMethodNames()); | ||||||
| 				setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod()); | 				setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod()); | ||||||
| 			} | 			} | ||||||
| 			setSynthetic(otherAbd.isSynthetic()); | 			setSynthetic(otherAbd.isSynthetic()); | ||||||
|  | @ -919,21 +919,41 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Set the name of the initializer method. | 	 * Specify the names of multiple initializer methods. | ||||||
| 	 * <p>The default is {@code null} in which case there is no initializer method. | 	 * <p>The default is {@code null} in which case there are no initializer methods. | ||||||
|  | 	 * @since 6.0 | ||||||
|  | 	 * @see #setInitMethodName | ||||||
| 	 */ | 	 */ | ||||||
| 	@Override | 	public void setInitMethodNames(@Nullable String... initMethodNames) { | ||||||
| 	public void setInitMethodName(@Nullable String initMethodName) { | 		this.initMethodNames = initMethodNames; | ||||||
| 		this.initMethodName = initMethodName; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Return the name of the initializer method. | 	 * Return the names of the initializer methods. | ||||||
|  | 	 * @since 6.0 | ||||||
|  | 	 */ | ||||||
|  | 	@Nullable | ||||||
|  | 	public String[] getInitMethodNames() { | ||||||
|  | 		return this.initMethodNames; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Set the name of the initializer method. | ||||||
|  | 	 * <p>The default is {@code null} in which case there is no initializer method. | ||||||
|  | 	 * @see #setInitMethodNames | ||||||
|  | 	 */ | ||||||
|  | 	@Override | ||||||
|  | 	public void setInitMethodName(@Nullable String initMethodName) { | ||||||
|  | 		this.initMethodNames = (initMethodName != null ? new String[] {initMethodName} : null); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Return the name of the initializer method (the first one in case of multiple methods). | ||||||
| 	 */ | 	 */ | ||||||
| 	@Override | 	@Override | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	public String getInitMethodName() { | 	public String getInitMethodName() { | ||||||
| 		return this.initMethodName; | 		return (!ObjectUtils.isEmpty(this.initMethodNames) ? this.initMethodNames[0] : null); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -958,21 +978,41 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Set the name of the destroy method. | 	 * Specify the names of multiple destroy methods. | ||||||
| 	 * <p>The default is {@code null} in which case there is no destroy method. | 	 * <p>The default is {@code null} in which case there are no destroy methods. | ||||||
|  | 	 * @since 6.0 | ||||||
|  | 	 * @see #setDestroyMethodName | ||||||
| 	 */ | 	 */ | ||||||
| 	@Override | 	public void setDestroyMethodNames(@Nullable String... destroyMethodNames) { | ||||||
| 	public void setDestroyMethodName(@Nullable String destroyMethodName) { | 		this.destroyMethodNames = destroyMethodNames; | ||||||
| 		this.destroyMethodName = destroyMethodName; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Return the name of the destroy method. | 	 * Return the names of the destroy methods. | ||||||
|  | 	 * @since 6.0 | ||||||
|  | 	 */ | ||||||
|  | 	@Nullable | ||||||
|  | 	public String[] getDestroyMethodNames() { | ||||||
|  | 		return this.destroyMethodNames; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Set the name of the destroy method. | ||||||
|  | 	 * <p>The default is {@code null} in which case there is no destroy method. | ||||||
|  | 	 * @see #setDestroyMethodNames | ||||||
|  | 	 */ | ||||||
|  | 	@Override | ||||||
|  | 	public void setDestroyMethodName(@Nullable String destroyMethodName) { | ||||||
|  | 		this.destroyMethodNames = (destroyMethodName != null ? new String[] {destroyMethodName} : null); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Return the name of the destroy method (the first one in case of multiple methods). | ||||||
| 	 */ | 	 */ | ||||||
| 	@Override | 	@Override | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	public String getDestroyMethodName() { | 	public String getDestroyMethodName() { | ||||||
| 		return this.destroyMethodName; | 		return (!ObjectUtils.isEmpty(this.destroyMethodNames) ? this.destroyMethodNames[0] : null); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -1189,9 +1229,9 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess | ||||||
| 				ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) && | 				ObjectUtils.nullSafeEquals(this.methodOverrides, that.methodOverrides) && | ||||||
| 				ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) && | 				ObjectUtils.nullSafeEquals(this.factoryBeanName, that.factoryBeanName) && | ||||||
| 				ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) && | 				ObjectUtils.nullSafeEquals(this.factoryMethodName, that.factoryMethodName) && | ||||||
| 				ObjectUtils.nullSafeEquals(this.initMethodName, that.initMethodName) && | 				ObjectUtils.nullSafeEquals(this.initMethodNames, that.initMethodNames) && | ||||||
| 				this.enforceInitMethod == that.enforceInitMethod && | 				this.enforceInitMethod == that.enforceInitMethod && | ||||||
| 				ObjectUtils.nullSafeEquals(this.destroyMethodName, that.destroyMethodName) && | 				ObjectUtils.nullSafeEquals(this.destroyMethodNames, that.destroyMethodNames) && | ||||||
| 				this.enforceDestroyMethod == that.enforceDestroyMethod && | 				this.enforceDestroyMethod == that.enforceDestroyMethod && | ||||||
| 				this.synthetic == that.synthetic && | 				this.synthetic == that.synthetic && | ||||||
| 				this.role == that.role && | 				this.role == that.role && | ||||||
|  | @ -1241,8 +1281,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess | ||||||
| 		sb.append("; primary=").append(this.primary); | 		sb.append("; primary=").append(this.primary); | ||||||
| 		sb.append("; factoryBeanName=").append(this.factoryBeanName); | 		sb.append("; factoryBeanName=").append(this.factoryBeanName); | ||||||
| 		sb.append("; factoryMethodName=").append(this.factoryMethodName); | 		sb.append("; factoryMethodName=").append(this.factoryMethodName); | ||||||
| 		sb.append("; initMethodName=").append(this.initMethodName); | 		sb.append("; initMethodNames=").append(this.initMethodNames); | ||||||
| 		sb.append("; destroyMethodName=").append(this.destroyMethodName); | 		sb.append("; destroyMethodNames=").append(this.destroyMethodNames); | ||||||
| 		if (this.resource != null) { | 		if (this.resource != null) { | ||||||
| 			sb.append("; defined in ").append(this.resource.getDescription()); | 			sb.append("; defined in ").append(this.resource.getDescription()); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -32,6 +32,7 @@ import org.springframework.lang.Nullable; | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
| import org.springframework.util.ClassUtils; | import org.springframework.util.ClassUtils; | ||||||
| import org.springframework.util.CollectionUtils; | import org.springframework.util.CollectionUtils; | ||||||
|  | import org.springframework.util.ObjectUtils; | ||||||
| import org.springframework.util.ReflectionUtils; | import org.springframework.util.ReflectionUtils; | ||||||
| import org.springframework.util.StringUtils; | import org.springframework.util.StringUtils; | ||||||
| 
 | 
 | ||||||
|  | @ -51,7 +52,7 @@ import org.springframework.util.StringUtils; | ||||||
|  * @see AbstractBeanFactory |  * @see AbstractBeanFactory | ||||||
|  * @see org.springframework.beans.factory.DisposableBean |  * @see org.springframework.beans.factory.DisposableBean | ||||||
|  * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor |  * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor | ||||||
|  * @see AbstractBeanDefinition#getDestroyMethodName() |  * @see AbstractBeanDefinition#getDestroyMethodNames() | ||||||
|  */ |  */ | ||||||
| @SuppressWarnings("serial") | @SuppressWarnings("serial") | ||||||
| class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
|  | @ -76,10 +77,10 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 	private boolean invokeAutoCloseable; | 	private boolean invokeAutoCloseable; | ||||||
| 
 | 
 | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private String destroyMethodName; | 	private String[] destroyMethodNames; | ||||||
| 
 | 
 | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private transient Method destroyMethod; | 	private transient Method[] destroyMethods; | ||||||
| 
 | 
 | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private final List<DestructionAwareBeanPostProcessor> beanPostProcessors; | 	private final List<DestructionAwareBeanPostProcessor> beanPostProcessors; | ||||||
|  | @ -103,14 +104,18 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 		this.invokeDisposableBean = (bean instanceof DisposableBean && | 		this.invokeDisposableBean = (bean instanceof DisposableBean && | ||||||
| 				!beanDefinition.isExternallyManagedDestroyMethod(DESTROY_METHOD_NAME)); | 				!beanDefinition.isExternallyManagedDestroyMethod(DESTROY_METHOD_NAME)); | ||||||
| 
 | 
 | ||||||
| 		String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition); | 		String[] destroyMethodNames = inferDestroyMethodsIfNecessary(bean, beanDefinition); | ||||||
| 		if (destroyMethodName != null && | 		if (!ObjectUtils.isEmpty(destroyMethodNames) && | ||||||
| 				!(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodName)) && | 				!(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodNames[0])) && | ||||||
| 				!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) { | 				!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodNames[0])) { | ||||||
| 
 | 
 | ||||||
| 			this.invokeAutoCloseable = (bean instanceof AutoCloseable && CLOSE_METHOD_NAME.equals(destroyMethodName)); | 			this.invokeAutoCloseable = | ||||||
|  | 					(bean instanceof AutoCloseable && CLOSE_METHOD_NAME.equals(destroyMethodNames[0])); | ||||||
| 			if (!this.invokeAutoCloseable) { | 			if (!this.invokeAutoCloseable) { | ||||||
| 				this.destroyMethodName = destroyMethodName; | 				this.destroyMethodNames = destroyMethodNames; | ||||||
|  | 				Method[] destroyMethods = new Method[destroyMethodNames.length]; | ||||||
|  | 				for (int i = 0; i < destroyMethodNames.length; i++) { | ||||||
|  | 					String destroyMethodName = destroyMethodNames[i]; | ||||||
| 					Method destroyMethod = determineDestroyMethod(destroyMethodName); | 					Method destroyMethod = determineDestroyMethod(destroyMethodName); | ||||||
| 					if (destroyMethod == null) { | 					if (destroyMethod == null) { | ||||||
| 						if (beanDefinition.isEnforceDestroyMethod()) { | 						if (beanDefinition.isEnforceDestroyMethod()) { | ||||||
|  | @ -132,7 +137,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 						} | 						} | ||||||
| 						destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod, bean.getClass()); | 						destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod, bean.getClass()); | ||||||
| 					} | 					} | ||||||
| 				this.destroyMethod = destroyMethod; | 					destroyMethods[i] = destroyMethod; | ||||||
|  | 				} | ||||||
|  | 				this.destroyMethods = destroyMethods; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -158,7 +165,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 	 * Create a new DisposableBeanAdapter for the given bean. | 	 * Create a new DisposableBeanAdapter for the given bean. | ||||||
| 	 */ | 	 */ | ||||||
| 	private DisposableBeanAdapter(Object bean, String beanName, boolean nonPublicAccessAllowed, | 	private DisposableBeanAdapter(Object bean, String beanName, boolean nonPublicAccessAllowed, | ||||||
| 			boolean invokeDisposableBean, boolean invokeAutoCloseable, @Nullable String destroyMethodName, | 			boolean invokeDisposableBean, boolean invokeAutoCloseable, @Nullable String[] destroyMethodNames, | ||||||
| 			@Nullable List<DestructionAwareBeanPostProcessor> postProcessors) { | 			@Nullable List<DestructionAwareBeanPostProcessor> postProcessors) { | ||||||
| 
 | 
 | ||||||
| 		this.bean = bean; | 		this.bean = bean; | ||||||
|  | @ -166,7 +173,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 		this.nonPublicAccessAllowed = nonPublicAccessAllowed; | 		this.nonPublicAccessAllowed = nonPublicAccessAllowed; | ||||||
| 		this.invokeDisposableBean = invokeDisposableBean; | 		this.invokeDisposableBean = invokeDisposableBean; | ||||||
| 		this.invokeAutoCloseable = invokeAutoCloseable; | 		this.invokeAutoCloseable = invokeAutoCloseable; | ||||||
| 		this.destroyMethodName = destroyMethodName; | 		this.destroyMethodNames = destroyMethodNames; | ||||||
| 		this.beanPostProcessors = postProcessors; | 		this.beanPostProcessors = postProcessors; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -219,13 +226,18 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		else if (this.destroyMethod != null) { | 		else if (this.destroyMethods != null) { | ||||||
| 			invokeCustomDestroyMethod(this.destroyMethod); | 			for (Method destroyMethod : this.destroyMethods) { | ||||||
|  | 				invokeCustomDestroyMethod(destroyMethod); | ||||||
| 			} | 			} | ||||||
| 		else if (this.destroyMethodName != null) { | 		} | ||||||
| 			Method destroyMethod = determineDestroyMethod(this.destroyMethodName); | 		else if (this.destroyMethodNames != null) { | ||||||
|  | 			for (String destroyMethodName: this.destroyMethodNames) { | ||||||
|  | 				Method destroyMethod = determineDestroyMethod(destroyMethodName); | ||||||
| 				if (destroyMethod != null) { | 				if (destroyMethod != null) { | ||||||
| 				invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(destroyMethod, this.bean.getClass())); | 					invokeCustomDestroyMethod( | ||||||
|  | 							ClassUtils.getInterfaceMethodIfPossible(destroyMethod, this.bean.getClass())); | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -255,14 +267,14 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 	 * for a method with a single boolean argument (passing in "true", | 	 * for a method with a single boolean argument (passing in "true", | ||||||
| 	 * assuming a "force" parameter), else logging an error. | 	 * assuming a "force" parameter), else logging an error. | ||||||
| 	 */ | 	 */ | ||||||
| 	private void invokeCustomDestroyMethod(final Method destroyMethod) { | 	private void invokeCustomDestroyMethod(Method destroyMethod) { | ||||||
| 		int paramCount = destroyMethod.getParameterCount(); | 		int paramCount = destroyMethod.getParameterCount(); | ||||||
| 		final Object[] args = new Object[paramCount]; | 		final Object[] args = new Object[paramCount]; | ||||||
| 		if (paramCount == 1) { | 		if (paramCount == 1) { | ||||||
| 			args[0] = Boolean.TRUE; | 			args[0] = Boolean.TRUE; | ||||||
| 		} | 		} | ||||||
| 		if (logger.isTraceEnabled()) { | 		if (logger.isTraceEnabled()) { | ||||||
| 			logger.trace("Invoking custom destroy method '" + this.destroyMethodName + | 			logger.trace("Invoking custom destroy method '" + destroyMethod.getName() + | ||||||
| 					"' on bean with name '" + this.beanName + "'"); | 					"' on bean with name '" + this.beanName + "'"); | ||||||
| 		} | 		} | ||||||
| 		try { | 		try { | ||||||
|  | @ -270,7 +282,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 			destroyMethod.invoke(this.bean, args); | 			destroyMethod.invoke(this.bean, args); | ||||||
| 		} | 		} | ||||||
| 		catch (InvocationTargetException ex) { | 		catch (InvocationTargetException ex) { | ||||||
| 			String msg = "Custom destroy method '" + this.destroyMethodName + "' on bean with name '" + | 			String msg = "Custom destroy method '" + destroyMethod.getName() + "' on bean with name '" + | ||||||
| 					this.beanName + "' threw an exception"; | 					this.beanName + "' threw an exception"; | ||||||
| 			if (logger.isDebugEnabled()) { | 			if (logger.isDebugEnabled()) { | ||||||
| 				logger.warn(msg, ex.getTargetException()); | 				logger.warn(msg, ex.getTargetException()); | ||||||
|  | @ -280,7 +292,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		catch (Throwable ex) { | 		catch (Throwable ex) { | ||||||
| 			logger.warn("Failed to invoke custom destroy method '" + this.destroyMethodName + | 			logger.warn("Failed to invoke custom destroy method '" + destroyMethod.getName() + | ||||||
| 					"' on bean with name '" + this.beanName + "'", ex); | 					"' on bean with name '" + this.beanName + "'", ex); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -302,7 +314,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 		} | 		} | ||||||
| 		return new DisposableBeanAdapter( | 		return new DisposableBeanAdapter( | ||||||
| 				this.bean, this.beanName, this.nonPublicAccessAllowed, this.invokeDisposableBean, | 				this.bean, this.beanName, this.nonPublicAccessAllowed, this.invokeDisposableBean, | ||||||
| 				this.invokeAutoCloseable, this.destroyMethodName, serializablePostProcessors); | 				this.invokeAutoCloseable, this.destroyMethodNames, serializablePostProcessors); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -312,7 +324,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 	 * @param beanDefinition the corresponding bean definition | 	 * @param beanDefinition the corresponding bean definition | ||||||
| 	 */ | 	 */ | ||||||
| 	public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) { | 	public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) { | ||||||
| 		return (bean instanceof DisposableBean || inferDestroyMethodIfNecessary(bean, beanDefinition) != null); | 		return (bean instanceof DisposableBean || inferDestroyMethodsIfNecessary(bean, beanDefinition) != null); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -330,7 +342,12 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 	 * interfaces, reflectively calling the "close" method on implementing beans as well. | 	 * interfaces, reflectively calling the "close" method on implementing beans as well. | ||||||
| 	 */ | 	 */ | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) { | 	private static String[] inferDestroyMethodsIfNecessary(Object bean, RootBeanDefinition beanDefinition) { | ||||||
|  | 		String[] destroyMethodNames = beanDefinition.getDestroyMethodNames(); | ||||||
|  | 		if (destroyMethodNames != null && destroyMethodNames.length > 1) { | ||||||
|  | 			return destroyMethodNames; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		String destroyMethodName = beanDefinition.resolvedDestroyMethodName; | 		String destroyMethodName = beanDefinition.resolvedDestroyMethodName; | ||||||
| 		if (destroyMethodName == null) { | 		if (destroyMethodName == null) { | ||||||
| 			destroyMethodName = beanDefinition.getDestroyMethodName(); | 			destroyMethodName = beanDefinition.getDestroyMethodName(); | ||||||
|  | @ -361,7 +378,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | ||||||
| 			} | 			} | ||||||
| 			beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : ""); | 			beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : ""); | ||||||
| 		} | 		} | ||||||
| 		return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null); | 		return (StringUtils.hasLength(destroyMethodName) ? new String[] {destroyMethodName} : null); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ import java.lang.reflect.Field; | ||||||
| import java.net.MalformedURLException; | import java.net.MalformedURLException; | ||||||
| import java.text.NumberFormat; | import java.text.NumberFormat; | ||||||
| import java.text.ParseException; | import java.text.ParseException; | ||||||
|  | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.Iterator; | import java.util.Iterator; | ||||||
|  | @ -2333,6 +2334,19 @@ class DefaultListableBeanFactoryTests { | ||||||
| 		assertThat(tb2.getBeanName()).isEqualTo("myBeanName"); | 		assertThat(tb2.getBeanName()).isEqualTo("myBeanName"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	@Test | ||||||
|  | 	void multipleInitAndDestroyMethods() { | ||||||
|  | 		RootBeanDefinition bd = new RootBeanDefinition(BeanWithInitAndDestroyMethods.class); | ||||||
|  | 		bd.setInitMethodNames("init1", "init2"); | ||||||
|  | 		bd.setDestroyMethodNames("destroy2", "destroy1"); | ||||||
|  | 		lbf.registerBeanDefinition("test", bd); | ||||||
|  | 		BeanWithInitAndDestroyMethods bean = lbf.getBean("test", BeanWithInitAndDestroyMethods.class); | ||||||
|  | 		assertThat(bean.initMethods).containsExactly("init", "init1", "init2"); | ||||||
|  | 		assertThat(bean.destroyMethods).isEmpty(); | ||||||
|  | 		lbf.destroySingletons(); | ||||||
|  | 		assertThat(bean.destroyMethods).containsExactly("destroy", "destroy2", "destroy1"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	void beanPostProcessorWithWrappedObjectAndDisposableBean() { | 	void beanPostProcessorWithWrappedObjectAndDisposableBean() { | ||||||
| 		RootBeanDefinition bd = new RootBeanDefinition(BeanWithDisposableBean.class); | 		RootBeanDefinition bd = new RootBeanDefinition(BeanWithDisposableBean.class); | ||||||
|  | @ -2758,9 +2772,42 @@ class DefaultListableBeanFactoryTests { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 	static class BeanWithInitAndDestroyMethods implements InitializingBean, DisposableBean { | ||||||
|  | 
 | ||||||
|  | 		final List<String> initMethods = new ArrayList<>(); | ||||||
|  | 		final List<String> destroyMethods = new ArrayList<>(); | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public void afterPropertiesSet() { | ||||||
|  | 			initMethods.add("init"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		void init1() { | ||||||
|  | 			initMethods.add("init1"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		void init2() { | ||||||
|  | 			initMethods.add("init2"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public void destroy() { | ||||||
|  | 			destroyMethods.add("destroy"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		void destroy1() { | ||||||
|  | 			destroyMethods.add("destroy1"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		void destroy2() { | ||||||
|  | 			destroyMethods.add("destroy2"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	public static class BeanWithDisposableBean implements DisposableBean { | 	public static class BeanWithDisposableBean implements DisposableBean { | ||||||
| 
 | 
 | ||||||
| 		private static boolean closed; | 		static boolean closed; | ||||||
| 
 | 
 | ||||||
| 		@Override | 		@Override | ||||||
| 		public void destroy() { | 		public void destroy() { | ||||||
|  | @ -2771,7 +2818,7 @@ class DefaultListableBeanFactoryTests { | ||||||
| 
 | 
 | ||||||
| 	public static class BeanWithCloseable implements Closeable { | 	public static class BeanWithCloseable implements Closeable { | ||||||
| 
 | 
 | ||||||
| 		private static boolean closed; | 		static boolean closed; | ||||||
| 
 | 
 | ||||||
| 		@Override | 		@Override | ||||||
| 		public void close() { | 		public void close() { | ||||||
|  | @ -2788,7 +2835,7 @@ class DefaultListableBeanFactoryTests { | ||||||
| 
 | 
 | ||||||
| 	public static class BeanWithDestroyMethod extends BaseClassWithDestroyMethod { | 	public static class BeanWithDestroyMethod extends BaseClassWithDestroyMethod { | ||||||
| 
 | 
 | ||||||
| 		private static int closeCount = 0; | 		static int closeCount = 0; | ||||||
| 
 | 
 | ||||||
| 		@SuppressWarnings("unused") | 		@SuppressWarnings("unused") | ||||||
| 		private BeanWithDestroyMethod inner; | 		private BeanWithDestroyMethod inner; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2020 the original author or authors. |  * Copyright 2002-2022 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -510,7 +510,7 @@ public class ScriptFactoryPostProcessor implements SmartInstantiationAwareBeanPo | ||||||
| 			Signature signature = new Signature(setterName, Type.VOID_TYPE, new Type[] {Type.getType(propertyType)}); | 			Signature signature = new Signature(setterName, Type.VOID_TYPE, new Type[] {Type.getType(propertyType)}); | ||||||
| 			maker.add(signature, new Type[0]); | 			maker.add(signature, new Type[0]); | ||||||
| 		} | 		} | ||||||
| 		if (bd.getInitMethodName() != null) { | 		if (StringUtils.hasText(bd.getInitMethodName())) { | ||||||
| 			Signature signature = new Signature(bd.getInitMethodName(), Type.VOID_TYPE, new Type[0]); | 			Signature signature = new Signature(bd.getInitMethodName(), Type.VOID_TYPE, new Type[0]); | ||||||
| 			maker.add(signature, new Type[0]); | 			maker.add(signature, new Type[0]); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2019 the original author or authors. |  * Copyright 2002-2022 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -22,8 +22,6 @@ import java.util.List; | ||||||
| 
 | 
 | ||||||
| import jakarta.annotation.PostConstruct; | import jakarta.annotation.PostConstruct; | ||||||
| import jakarta.annotation.PreDestroy; | import jakarta.annotation.PreDestroy; | ||||||
| import org.apache.commons.logging.Log; |  | ||||||
| import org.apache.commons.logging.LogFactory; |  | ||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
| 
 | 
 | ||||||
| import org.springframework.beans.factory.DisposableBean; | import org.springframework.beans.factory.DisposableBean; | ||||||
|  | @ -35,15 +33,12 @@ import org.springframework.util.ObjectUtils; | ||||||
| import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * <p> |  * Unit test which verifies expected <em>init</em> and <em>destroy</em> | ||||||
|  * JUnit-3.8-based unit test which verifies expected <em>init</em> and |  * bean lifecycle behavior as requested in | ||||||
|  * <em>destroy</em> bean lifecycle behavior as requested in <a |  * <a href="https://opensource.atlassian.com/projects/spring/browse/SPR-3775" | ||||||
|  * href="https://opensource.atlassian.com/projects/spring/browse/SPR-3775" |  | ||||||
|  * target="_blank">SPR-3775</a>. |  * target="_blank">SPR-3775</a>. | ||||||
|  * </p> |  * | ||||||
|  * <p> |  * <p>Specifically, combinations of the following are tested: | ||||||
|  * Specifically, combinations of the following are tested: |  | ||||||
|  * </p> |  | ||||||
|  * <ul> |  * <ul> | ||||||
|  * <li>{@link InitializingBean} & {@link DisposableBean} interfaces</li> |  * <li>{@link InitializingBean} & {@link DisposableBean} interfaces</li> | ||||||
|  * <li>Custom {@link RootBeanDefinition#getInitMethodName() init} & |  * <li>Custom {@link RootBeanDefinition#getInitMethodName() init} & | ||||||
|  | @ -57,26 +52,17 @@ import static org.assertj.core.api.Assertions.assertThat; | ||||||
|  */ |  */ | ||||||
| public class Spr3775InitDestroyLifecycleTests { | public class Spr3775InitDestroyLifecycleTests { | ||||||
| 
 | 
 | ||||||
| 	private static final Log logger = LogFactory.getLog(Spr3775InitDestroyLifecycleTests.class); |  | ||||||
| 
 |  | ||||||
| 	/** LIFECYCLE_TEST_BEAN. */ |  | ||||||
| 	private static final String LIFECYCLE_TEST_BEAN = "lifecycleTestBean"; | 	private static final String LIFECYCLE_TEST_BEAN = "lifecycleTestBean"; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	private void debugMethods(Class<?> clazz, String category, List<String> methodNames) { | 	private void assertMethodOrdering(String category, List<String> expectedMethods, List<String> actualMethods) { | ||||||
| 		if (logger.isDebugEnabled()) { | 		assertThat(ObjectUtils.nullSafeEquals(expectedMethods, actualMethods)). | ||||||
| 			logger.debug(clazz.getSimpleName() + ": " + category + ": " + methodNames); | 				as("Verifying " + category + ": expected<" + expectedMethods + "> but got<" + actualMethods + ">.").isTrue(); | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private void assertMethodOrdering(Class<?> clazz, String category, List<String> expectedMethods, | 	private DefaultListableBeanFactory createBeanFactoryAndRegisterBean( | ||||||
| 			List<String> actualMethods) { | 			Class<?> beanClass, String initMethodName, String destroyMethodName) { | ||||||
| 		debugMethods(clazz, category, actualMethods); |  | ||||||
| 		assertThat(ObjectUtils.nullSafeEquals(expectedMethods, actualMethods)).as("Verifying " + category + ": expected<" + expectedMethods + "> but got<" + actualMethods + ">.").isTrue(); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	private DefaultListableBeanFactory createBeanFactoryAndRegisterBean(final Class<?> beanClass, |  | ||||||
| 			final String initMethodName, final String destroyMethodName) { |  | ||||||
| 		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); | 		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); | ||||||
| 		RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); | 		RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); | ||||||
| 		beanDefinition.setInitMethodName(initMethodName); | 		beanDefinition.setInitMethodName(initMethodName); | ||||||
|  | @ -88,75 +74,77 @@ public class Spr3775InitDestroyLifecycleTests { | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void testInitDestroyMethods() { | 	public void testInitDestroyMethods() { | ||||||
| 		final Class<?> beanClass = InitDestroyBean.class; | 		Class<?> beanClass = InitDestroyBean.class; | ||||||
| 		final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, | 		DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, | ||||||
| 				"afterPropertiesSet", "destroy"); | 				"afterPropertiesSet", "destroy"); | ||||||
| 		final InitDestroyBean bean = (InitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | 		InitDestroyBean bean = (InitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | ||||||
| 		assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods); | 		assertMethodOrdering("init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods); | ||||||
| 		beanFactory.destroySingletons(); | 		beanFactory.destroySingletons(); | ||||||
| 		assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy"), bean.destroyMethods); | 		assertMethodOrdering("destroy-methods", Arrays.asList("destroy"), bean.destroyMethods); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void testInitializingDisposableInterfaces() { | 	public void testInitializingDisposableInterfaces() { | ||||||
| 		final Class<?> beanClass = CustomInitializingDisposableBean.class; | 		Class<?> beanClass = CustomInitializingDisposableBean.class; | ||||||
| 		final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", | 		DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", | ||||||
| 				"customDestroy"); | 				"customDestroy"); | ||||||
| 		final CustomInitializingDisposableBean bean = (CustomInitializingDisposableBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | 		CustomInitializingDisposableBean bean = (CustomInitializingDisposableBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | ||||||
| 		assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet", "customInit"), | 		assertMethodOrdering("init-methods", Arrays.asList("afterPropertiesSet", "customInit"), | ||||||
| 				bean.initMethods); | 				bean.initMethods); | ||||||
| 		beanFactory.destroySingletons(); | 		beanFactory.destroySingletons(); | ||||||
| 		assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy", "customDestroy"), | 		assertMethodOrdering("destroy-methods", Arrays.asList("destroy", "customDestroy"), | ||||||
| 				bean.destroyMethods); | 				bean.destroyMethods); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void testInitializingDisposableInterfacesWithShadowedMethods() { | 	public void testInitializingDisposableInterfacesWithShadowedMethods() { | ||||||
| 		final Class<?> beanClass = InitializingDisposableWithShadowedMethodsBean.class; | 		Class<?> beanClass = InitializingDisposableWithShadowedMethodsBean.class; | ||||||
| 		final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, | 		DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, | ||||||
| 				"afterPropertiesSet", "destroy"); | 				"afterPropertiesSet", "destroy"); | ||||||
| 		final InitializingDisposableWithShadowedMethodsBean bean = (InitializingDisposableWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | 		InitializingDisposableWithShadowedMethodsBean bean = | ||||||
| 		assertMethodOrdering(beanClass, "init-methods", Arrays.asList("InitializingBean.afterPropertiesSet"), | 				(InitializingDisposableWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | ||||||
|  | 		assertMethodOrdering("init-methods", Arrays.asList("InitializingBean.afterPropertiesSet"), | ||||||
| 				bean.initMethods); | 				bean.initMethods); | ||||||
| 		beanFactory.destroySingletons(); | 		beanFactory.destroySingletons(); | ||||||
| 		assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("DisposableBean.destroy"), bean.destroyMethods); | 		assertMethodOrdering("destroy-methods", Arrays.asList("DisposableBean.destroy"), bean.destroyMethods); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void testJsr250Annotations() { | 	public void testJsr250Annotations() { | ||||||
| 		final Class<?> beanClass = CustomAnnotatedInitDestroyBean.class; | 		Class<?> beanClass = CustomAnnotatedInitDestroyBean.class; | ||||||
| 		final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", | 		DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", | ||||||
| 				"customDestroy"); | 				"customDestroy"); | ||||||
| 		final CustomAnnotatedInitDestroyBean bean = (CustomAnnotatedInitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | 		CustomAnnotatedInitDestroyBean bean = (CustomAnnotatedInitDestroyBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | ||||||
| 		assertMethodOrdering(beanClass, "init-methods", Arrays.asList("postConstruct", "afterPropertiesSet", | 		assertMethodOrdering("init-methods", Arrays.asList("postConstruct", "afterPropertiesSet", | ||||||
| 				"customInit"), bean.initMethods); | 				"customInit"), bean.initMethods); | ||||||
| 		beanFactory.destroySingletons(); | 		beanFactory.destroySingletons(); | ||||||
| 		assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("preDestroy", "destroy", "customDestroy"), | 		assertMethodOrdering("destroy-methods", Arrays.asList("preDestroy", "destroy", "customDestroy"), | ||||||
| 				bean.destroyMethods); | 				bean.destroyMethods); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void testJsr250AnnotationsWithShadowedMethods() { | 	public void testJsr250AnnotationsWithShadowedMethods() { | ||||||
| 		final Class<?> beanClass = CustomAnnotatedInitDestroyWithShadowedMethodsBean.class; | 		Class<?> beanClass = CustomAnnotatedInitDestroyWithShadowedMethodsBean.class; | ||||||
| 		final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", | 		DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", | ||||||
| 				"customDestroy"); | 				"customDestroy"); | ||||||
| 		final CustomAnnotatedInitDestroyWithShadowedMethodsBean bean = (CustomAnnotatedInitDestroyWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | 		CustomAnnotatedInitDestroyWithShadowedMethodsBean bean = | ||||||
| 		assertMethodOrdering(beanClass, "init-methods", | 				(CustomAnnotatedInitDestroyWithShadowedMethodsBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | ||||||
|  | 		assertMethodOrdering("init-methods", | ||||||
| 				Arrays.asList("@PostConstruct.afterPropertiesSet", "customInit"), bean.initMethods); | 				Arrays.asList("@PostConstruct.afterPropertiesSet", "customInit"), bean.initMethods); | ||||||
| 		beanFactory.destroySingletons(); | 		beanFactory.destroySingletons(); | ||||||
| 		assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("@PreDestroy.destroy", "customDestroy"), | 		assertMethodOrdering("destroy-methods", Arrays.asList("@PreDestroy.destroy", "customDestroy"), | ||||||
| 				bean.destroyMethods); | 				bean.destroyMethods); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void testAllLifecycleMechanismsAtOnce() { | 	public void testAllLifecycleMechanismsAtOnce() { | ||||||
| 		final Class<?> beanClass = AllInOneBean.class; | 		Class<?> beanClass = AllInOneBean.class; | ||||||
| 		final DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, | 		DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, | ||||||
| 				"afterPropertiesSet", "destroy"); | 				"afterPropertiesSet", "destroy"); | ||||||
| 		final AllInOneBean bean = (AllInOneBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | 		AllInOneBean bean = (AllInOneBean) beanFactory.getBean(LIFECYCLE_TEST_BEAN); | ||||||
| 		assertMethodOrdering(beanClass, "init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods); | 		assertMethodOrdering("init-methods", Arrays.asList("afterPropertiesSet"), bean.initMethods); | ||||||
| 		beanFactory.destroySingletons(); | 		beanFactory.destroySingletons(); | ||||||
| 		assertMethodOrdering(beanClass, "destroy-methods", Arrays.asList("destroy"), bean.destroyMethods); | 		assertMethodOrdering("destroy-methods", Arrays.asList("destroy"), bean.destroyMethods); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -165,7 +153,6 @@ public class Spr3775InitDestroyLifecycleTests { | ||||||
| 		final List<String> initMethods = new ArrayList<>(); | 		final List<String> initMethods = new ArrayList<>(); | ||||||
| 		final List<String> destroyMethods = new ArrayList<>(); | 		final List<String> destroyMethods = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 		public void afterPropertiesSet() throws Exception { | 		public void afterPropertiesSet() throws Exception { | ||||||
| 			this.initMethods.add("afterPropertiesSet"); | 			this.initMethods.add("afterPropertiesSet"); | ||||||
| 		} | 		} | ||||||
|  | @ -175,8 +162,9 @@ public class Spr3775InitDestroyLifecycleTests { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public static class InitializingDisposableWithShadowedMethodsBean extends InitDestroyBean implements | 
 | ||||||
| 			InitializingBean, DisposableBean { | 	public static class InitializingDisposableWithShadowedMethodsBean extends InitDestroyBean | ||||||
|  | 			implements InitializingBean, DisposableBean { | ||||||
| 
 | 
 | ||||||
| 		@Override | 		@Override | ||||||
| 		public void afterPropertiesSet() throws Exception { | 		public void afterPropertiesSet() throws Exception { | ||||||
|  | @ -255,14 +243,14 @@ public class Spr3775InitDestroyLifecycleTests { | ||||||
| 		final List<String> initMethods = new ArrayList<>(); | 		final List<String> initMethods = new ArrayList<>(); | ||||||
| 		final List<String> destroyMethods = new ArrayList<>(); | 		final List<String> destroyMethods = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
| 		@Override |  | ||||||
| 		@PostConstruct | 		@PostConstruct | ||||||
|  | 		@Override | ||||||
| 		public void afterPropertiesSet() throws Exception { | 		public void afterPropertiesSet() throws Exception { | ||||||
| 			this.initMethods.add("afterPropertiesSet"); | 			this.initMethods.add("afterPropertiesSet"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		@Override |  | ||||||
| 		@PreDestroy | 		@PreDestroy | ||||||
|  | 		@Override | ||||||
| 		public void destroy() throws Exception { | 		public void destroy() throws Exception { | ||||||
| 			this.destroyMethods.add("destroy"); | 			this.destroyMethods.add("destroy"); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue