【Spring boot读书笔记】 SpringApplication-运行阶段(3):Spring内建事件及自定义事件

Spring内建事件

Spring容器启动过程中,针对启动的各个阶段定义了对应的内建事件:

  • ContextRefreshedEvent : Spring应用上下文就绪事件
  • ContextStartedEvent Spring应用上下文启动事件
  • ContextStoppedEvent Spring应用上下文停止事件
  • ContextClosedEvent Spring应用上下文关闭事件
(1)ContextRefreshedEvent

ContextRefreshedEvent在ConfigurableApplicationContext.refresh() 完成时触发,源码如下:


public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean {
	...
	
    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                
                // 1.初始化事件广播器
                this.initApplicationEventMulticaster();
                this.onRefresh();
                
                // 2.注册ApplicationListener
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                // 3.ContextRefreshedEvent
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

	// 发布事件
	protected void finishRefresh() {
		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

}
(2)ContextStartedEvent &ContextStoppedEvent

ContextStartedEvent 和 ContextStoppedEvent,比较罕见,两者分别在AbstractApplicationContext.start() 和AbstractApplicationContext.stop()方法中发布:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext, DisposableBean {
		
	...
	
	// 启动:ContextStartedEvent  
	@Override
	public void start() {
		getLifecycleProcessor().start();
		publishEvent(new ContextStartedEvent(this));
	}

	// 关闭:ContextStoppedEvent
	@Override
	public void stop() {
		getLifecycleProcessor().stop();
		publishEvent(new ContextStoppedEvent(this));
	}
	
	...
}

在绝大多数场景中,start()和stop()不会被调用,然而并不意味着他们没有存在的价值:

  • AbstractApplicationContext.start() --> LifecycleProcessor.start() --> LifecycleBean.start()
  • AbstractApplicationContext.stop() --> LifecycleProcessor.stop() --> LifecycleBean.stop()

通过控制ApplicationContext启停最终能触发LifecycleBean的启停:


// 自动组件接口:Lifecycle 
public interface Lifecycle {
	void start();
	void stop();
	boolean isRunning();

}

public interface LifecycleProcessor extends Lifecycle {
	 // 通知自动组件启动
	void onRefresh();
	// 通知自动组件关闭
	void onClose();

}

对应这两个事件实际的应用,可以在SpringCloud resume 和pause Endpoint中找到

@Endpoint(id = "restart", enableByDefault = false)
public class RestartEndpoint implements ApplicationListener<ApplicationPreparedEvent> {
	...
	
	// Spring 上下文	
	private ConfigurableApplicationContext context;

	public PauseEndpoint getPauseEndpoint() {
		return new PauseEndpoint();
	}

	public ResumeEndpoint getResumeEndpoint() {
		return new ResumeEndpoint();
	}

	@Endpoint(id = "pause")
	public class PauseEndpoint {

		@WriteOperation
		public Boolean pause() {
			if (isRunning()) {
				doPause();
				return true;
			}
			return false;
		}
	}

	@Endpoint(id = "resume")
	@ConfigurationProperties("management.endpoint.resume")
	public class ResumeEndpoint {

		@WriteOperation
		public Boolean resume() {
			if (!isRunning()) {
				doResume();
				return true;
			}
			return false;
		}
	}

	// 重启,调用close() 
	public synchronized ConfigurableApplicationContext doRestart() {
		if (this.context != null) {
			if (this.integrationShutdown != null) {
				this.integrationShutdown.stop(this.timeout);
			}
			this.application.setEnvironment(this.context.getEnvironment());
			close();
			// If running in a webapp then the context classloader is probably going to
			// die so we need to revert to a safe place before starting again
			overrideClassLoaderForRestart();
			this.context = this.application.run(this.args);
		}
		return this.context;
	}
	
	...

	// 触发ContextStoppedEvent
	public synchronized void doPause() {
		if (this.context != null) {
			this.context.stop();
		}
	}

	// 触发ContextStartedEvent  
	public synchronized void doResume() {
		if (this.context != null) {
			this.context.start();
		}
	}

	...

}

(3) ContextCloseEvent

ContextCloseEvent事件与ContextRefreshedEvent正好相反,它有


public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext, DisposableBean {
	@Override
	public void close() {
		synchronized (this.startupShutdownMonitor) {
			doClose();
			// If we registered a JVM shutdown hook, we don't need it anymore now:
			// We've already explicitly closed the context.
			if (this.shutdownHook != null) {
				try {
					Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
				}
				catch (IllegalStateException ex) {
					// ignore - VM is already shutting down
				}
			}
		}
	}
	
	// 触发ContextClosedEvent
	protected void doClose() {
		if (this.active.get() && this.closed.compareAndSet(false, true)) {
			if (logger.isInfoEnabled()) {
				logger.info("Closing " + this);
			}

			LiveBeansView.unregisterApplicationContext(this);

			try {
				// Publish shutdown event.
				publishEvent(new ContextClosedEvent(this));
			}
			catch (Throwable ex) {
				logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
			}

			// Stop all Lifecycle beans, to avoid delays during individual destruction.
			try {
				getLifecycleProcessor().onClose();
			}
			catch (Throwable ex) {
				logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
			}

			// Destroy all cached singletons in the context's BeanFactory.
			destroyBeans();

			// Close the state of this context itself.
			closeBeanFactory();

			// Let subclasses do some final clean-up if they wish...
			onClose();

			this.active.set(false);
		}
	}
}

自定义Spring事件

自定义Spring事件,继承ApplicationEvent即可:

  public class MyApplicationEvent extends ApplicationEvent {

      public MyApplicationEvent(String source) {
          super(source);
      }
  }

事件的发布听过ApplicationEventPublisher.publishEvent(), 而Application默认实现了ApplicationEventPublisher接口,所以自定义事件,可以直接通过Spring Context发布:


public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值