什么是Spring的扩展点? 这个问题让我很深刻,记得之前有一个面试就被问到有没有使用过。 那他是什么? 先来看下Spring容器的加载过程 可以看到Bean从无到有主要是经历了四个步骤 就是在成熟态的时候,在初始化生命周期执行回调方法 主要是以接口或者注解的形式对外提供,注入到IOC容器中,完成对应的功能。哪些场景下,我们需要使用退出前销毁 主要是希望在销毁之前在做一些事情,比如像池化技术正确的断开,JVM内存回收,还有业务逻辑执行。业务场景 直接进入正题,我先说一说我的业务场景,在执行任务A的时候,这时候服务重启了,因为任务A加了分布式锁,所以在 重启服务的时候,补偿机制拿到了任务A发现锁依然被占用着,所以我就希望能够在应用关闭之前把锁给释放掉,减少 对补偿机制的影响。 补充:这里其实也可以用Redisson,来进行锁续期,一段时间过后自己释放,但是系统中更多时候使用简单的分布式 锁就可以满足,避免引入Redisson这么重的框架。解决方案将当前执行任务的redis锁记录下来在Spring应用关系的时候,调用销毁方法进行锁的释放采用SmartLifecycle和DisposableBean相互配合来执行destroy()方法 具体实现:ServicepublicclassUserServiceImplimplementsUserService,DisposableBean,SmartLifecycle{privatevolatilebooleanrunningfalse;privateListStringlockKeysnewArrayList();ResourceHelloServicehelloService;Overridepublicvoidget(){Stringkeyredis:key;伪代码RedissonUtil。lock(key);try{lockKeys。add(key);}catch(Exceptionex){ex。printStackTrace();。。。}finally{RedissonUtil。unlock(key);lockKeys。remove(key);}}Overridepublicvoiddestroy(){删除正在执行中的keyRedissonUtil。deletes(lockKeys);runningfalse;}Overridepublicvoidstart(){System。out。println(start);runningtrue;}Overridepublicvoidstop(){System。out。println(stop);删除正在执行中的keyRedissonUtil。deletes(lockKeys);}OverridepublicbooleanisRunning(){returnrunning;}OverridepublicintgetPhase(){returnInteger。MAXVALUE;}}复制代码 利用DisposableBean和SmartLifecycle进行双重的销毁机制,如果已经执行了DisposableBean的销毁方法 那可以修改running的值为false,就不会再进行stop()的执行了Spring执行关闭的时机JVM关闭对象销毁时候容器停止关闭前执行销毁方法有哪些DisposableBean 调用时机:Bean对象销毁的时候ServicepublicclassUserServiceImplimplementsUserService,DisposableBean{Overridepublicvoiddestroy(){System。out。println(destroy);}}复制代码SmartLifecycle 调用时机:Spring容器发出关闭通知ServicepublicclassUserServiceImplimplementsUserService,SmartLifecycle{Overridepublicvoidstart(){System。out。println(start);runningtrue;}Overridepublicvoidstop(){System。out。println(stop);}OverridepublicbooleanisRunning(){returnrunning;}OverridepublicintgetPhase(){returnInteger。MAXVALUE;}}复制代码InitializingBean 这个方式比较特殊,就是在初始化的时候,提前设置好了钩子函数addShutdownHook 调用时机:监听到JVM关闭ServicepublicclassUserServiceImplimplementsUserService,InitializingBean{OverridepublicvoidafterPropertiesSet(){Runtime。getRuntime()。addShutdownHook(newThread((){helloService。get();System。out。println(addShutdownHook);}));}}复制代码PreDestroy注解PreDestroypublicvoidpreDestroy(){System。out。println(PreDestroy);}复制代码Xml和Bean绑定destoryMethod方法 对比执行结果: SmartLifecyclePreDestroy,DisposableBeanaddShutdownHook2022090523:06:04。046INFO11807〔main〕c。l。d。SpringBootDemoDockerApplication:StartedSpringBootDemoDockerApplicationin1。4seconds(JVMrunningfor1。752)ApplicationRunnerCommandLineRunner项目启动完毕后,倒数10秒关闭thread1。。。thread1。。。thread1。。。thread1。。。stop2022090523:06:14。054INFO11807〔main〕o。s。s。concurrent。ThreadPoolTaskExecutor:ShuttingdownExecutorServiceapplicationTaskExecutorPreDestroydestroythread1。。。thread1。。。getaddShutdownHook复制代码SmartLifecycle接口源码 了解一下SmartLifecycle接口到底由哪些组成的当上下文被刷新(所有对象已被实例化和初始化之后)时,将调用该方法isAutoStartup默认为true则调用start,否则需要自己手动调用Overridepublicvoidstart(){System。out。println(start);runningtrue;}接口Lifecycle子类的方法,只有非SmartLifecycle的子类才会执行该方法。1。该方法只对直接实现接口Lifecycle的类才起作用,对实现SmartLifecycle接口的类无效。2。方法stop()和方法stop(Runnablecallback)的区别只在于,后者是SmartLifecycle子类的专属。Overridepublicvoidstop(){System。out。println(stop);}只有该方法返回false时,start方法才会被执行只有该方法返回true时,stop(Runnablecallback)或stop()方法才会被执returnOverridepublicbooleanisRunning(){returnrunning;}返回Integer。MAXVALUE仅表明我们将是第一个关闭的bean和最后一个启动的bean关闭容器的第一时间调用stop()方法OverridepublicintgetPhase(){returnInteger。MAXVALUE;}如果该Lifecycle类所在的上下文在调用refresh时,希望能够自己自动进行回调,则返回true,false的值表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。OverridepublicbooleanisAutoStartup(){returnfalse;}SmartLifecycle子类的才有的方法,当isRunning方法返回true时,该方法才会被调用。很多框架中的源码中,都会把真正逻辑写在stop()方法内。Overridepublicvoidstop(Runnablecallback){stop();如果你让isRunning返回true,需要执行stop这个方法在程序退出时,Spring的DefaultLifecycleProcessor会认为这个MySmartLifecycle没有stop完成,程序会一直卡着结束不了,等待一定时间(默认超时时间30秒)后才会自动结束。callback。run();}复制代码 SmartLifecycleisRunning判断是否已经执行,false表示还未执行 则调用SmartLifecyclestart()执行 当关闭的时候isRunning为ture已经执行 则调用SmartLifecyclestop()执行学习MQ如何进行退出前优雅执行销毁方法 DefaultRocketMQListenerContainer。classpublicclassDefaultRocketMQListenerContainerimplementsInitializingBean,RocketMQListenerContainer,SmartLifecycle,ApplicationContextAware{privatefinalstaticLoggerlogLoggerFactory。getLogger(DefaultRocketMQListenerContainer。class);privatebooleanrunning;。。。Overridepublicvoiddestroy(){this。setRunning(false);if(Objects。nonNull(consumer)){consumer。shutdown();}log。info(containerdestroyed,{},this。toString());}OverridepublicbooleanisAutoStartup(){returntrue;}Overridepublicvoidstop(Runnablecallback){stop();callback。run();}Overridepublicvoidstart(){if(this。isRunning()){thrownewIllegalStateException(containeralreadyrunning。this。toString());}try{consumer。start();}catch(MQClientExceptione){thrownewIllegalStateException(FailedtostartRocketMQpushconsumer,e);}this。setRunning(true);log。info(runningcontainer:{},this。toString());}Overridepublicvoidstop(){if(this。isRunning()){if(Objects。nonNull(consumer)){consumer。shutdown();}setRunning(false);}}OverridepublicbooleanisRunning(){returnrunning;}privatevoidsetRunning(booleanrunning){this。runningrunning;}OverridepublicintgetPhase(){ReturningInteger。MAXVALUEonlysuggeststhatwewillbethefirstbeantoshutdownandlastbeantostartreturnInteger。MAXVALUE;}OverridepublicvoidafterPropertiesSet()throwsException{initRocketMQPushConsumer();this。messageTypegetMessageType();this。methodParametergetMethodParameter();log。debug(RocketMQmessageType:{},messageType);}}复制代码 RocketMQ在这里进行了几个步骤需要我们关注他将getPhase的值设置为最大,在容器关闭的第一时间调用stop()方法同时实现了SmartLifecycle和RocketMQListenerContainer接口,分别实现了stop()和destroy()方法,进行双重关闭,如果和destroy()先执行了,则将running设置为false,不再执行stop() 原文链接:https:juejin。cnpost7139920679683489823