DerekYRC/mini-spring

初始化与销毁方法中,只避免销毁方法执行两次而初始化方法没有相关的判断

Whale-lyi opened this issue · 1 comments

DisposableBeanAdapter#destroy() 会通过判断避免 bean 继承自 DisposableBean ,且自定方法与 DisposableBean 方法同名导致销毁方法方法执行两次,代码如下

@Override
public void destroy() throws Exception {
    if (bean instanceof DisposableBean) {
	    ((DisposableBean) bean).destroy();
    }

    //避免同时继承自DisposableBean,且自定义方法与DisposableBean方法同名,销毁方法执行两次的情况
    if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) {
	    //执行自定义方法
	    Method destroyMethod = ClassUtil.getPublicMethod(bean.getClass(), destroyMethodName);
	    if (destroyMethod == null) {
		    throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
	    }
	    destroyMethod.invoke(bean);
    }
}

而 AbstractAutowireCapableBeanFactory#invokeInitMethods() 中缺少类似判断,会导致初始化方法执行两次,代码如下

protected void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Throwable {
    if (bean instanceof InitializingBean) {
	    ((InitializingBean) bean).afterPropertiesSet();
    }
    String initMethodName = beanDefinition.getInitMethodName();
    if (StrUtil.isNotEmpty(initMethodName)) {
	    Method initMethod = ClassUtil.getPublicMethod(beanDefinition.getBeanClass(), initMethodName);
	    if (initMethod == null) {
		    throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
	    }
	    initMethod.invoke(bean);
    }
}

在查看spring-framework 5.3.x 源码后可以发现源码是做了相关的判断的,如下

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
			}
			if (System.getSecurityManager() != null) {
				try {
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				((InitializingBean) bean).afterPropertiesSet();
			}
		}
                // 在这里做了判断
		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

@Whale-lyi Hi, 感谢你的提醒,有时间可以提个pull request哦