记Spring Bean的坑

在一次项目中发现了一个不正常的现象,弄了半天才弄明白咋回事,当初手贱瞎写,造成的困扰。不多说,来一起看下。
由于业务的需要我定义了一个类,其作用协议传输数据之用。

public class Transmission {
    
    public void comd1(){
        System.out.println("发送命令1");
    }

    public void comd2(){
        System.out.println("发送命令2");
    }

    public void shutdown(){
        System.out.println("发送关机命令");
    }
}

然后做了一个配置类,对这个类进行初始化和注册到Spring进行管理。

@Configuration
public class TransmissionConfig {
    @Bean
    public Transmission getTransmission(){
        return new Transmission();
    }
}

然后在需要他的地方调用运行它,好了这样写没有问题,能稳定运行。
奇怪的事情也接踵而来。在测试环境中,每一次项目重构发版,就会导致所有连接设备都关机了。然后各种查问题,将设备中的日志读取出来,根据时间点的信息,发现是服务端发送了关机的命令。
然后我懵逼了,将所有调用关机命令的地方都屏蔽了,还是会出现这种现象。
然后更懵逼了,明明没调用为什么就会发送指令??
既然是在项目关闭时候发生的,那有没有可能是指定了这个Bean的注销前调用的方法,既xml注册时指定的destroy-method;或注解注入时,指定@PreDestroy方法;或实现了DisposableBean接口。这样的话,在Bean的生命周期结束前会自动调用这个些方法,然后再释放Bean,然而都没有。
那只能分离出最小代码,然后再一步一步查打断点查原因喽。
终于在坚持不懈中找的了原因,在Spring的Bean注册的时候,会判断,当前应该注册成DisposableBean。如果类实现了DisposableBean接口或者实现了AutoCloseable接口或者注册时指定了destroy-method方法,那自然而然注册成DisposableBean,在生命周期结束的时候调用对应的方法。
但是,虽然没有继承这些方法也没关系,只要有名字叫close或者shutdown方法,也是可以注册的。这就是害死我的地方。

/**
	 * 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 || bean instanceof AutoCloseable) {
			return true;
		}
		String destroyMethodName = beanDefinition.getDestroyMethodName();
		if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
			return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
					ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
		}
		return StringUtils.hasLength(destroyMethodName);
	}

在org.springframework.beans.factory.support.DisposableBeanAdapter#hasDestroyMethod中。适用于Bean类型是single的。而且close方法的优先级大于shutdown。
所以只能把通讯类改成下面这种形式:

public class Transmission {
    
    public void comd1(){
        System.out.println("发送命令1");
    }

    public void comd2(){
        System.out.println("发送命令2");
    }

    public void equipmentShutdown(){
        System.out.println("发送关机命令");
    }
}

总结:
如果不是在Bean中特殊指定成为DisposableBean,请不要写有close和shutdown的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值