Spring的ApplicationListener和ApplicationContext的使用

Spring 提供了两种类型的 IOC 容器实现.

  • BeanFactory :是Spring实现IOC容器的顶级接口,主要供Spring内部使用,并非面向spring框架的开发者
  • ApplicationContext : 是 BeanFactory 的子接口,提供了更多的高级特性。主要面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory

在ApplicationContext接口中有三个常用的实现类分别是:
①、AnnotationConfigApplicationContext
②、FileSystemXmlApplicationContext
③、ClassPathXmlApplicationContext

1、ApplicationContextAware

Spring定义的类实现ApplicationContextAware接口会自动的将应用程序上下文加入。

代码示例如下:

@Slf4j
@Component
public class ApplicationConfig implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        log.info("{} 服务初始化完成!!!", this.applicationContext.getApplicationName());
    }

}

spring 的入口方法就在 AbstractApplicationContextrefresh() 方法,我们先去看看refresh().prepareBeanFactory()方法。

org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		if (!shouldIgnoreSpel) {
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);


		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
		if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
			beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
		}
	}

spring在 启动的时候给我们添加了 ApplicationContextAwareProcessor 这样一个 processor,看它的实现。

@Override
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
				bean instanceof ApplicationStartupAware)) {
			return bean;
		}

		AccessControlContext acc = null;

		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}
private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationStartupAware) {
			((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

可清楚了解到ApplicationContextAware实现类在应用启动的时候就自动初始化了

2、ApplicationListener

ApplicationContext事件机制是属于设计模式中的观察者设计模式,通过ApplicationEvent类和ApplicationListener接口实现事件处理。

当容器中有一个ApplicationListener对象, 当ApplicationContext发布ApplicationEvent事件时,ApplicationListener对象会被自动触发, 需要由程序来控制。

spring内置事件

内置事件说明适用场景
ContextRefreshedEventApplicationContext 被初始化或刷新时,该事件被发布。也可在 ConfigurableApplicationContext接口中使用 refresh() 方法来触发。初始化是指:所有的Bean被成功装载,容器已就绪可用初始化缓存、预加载数据等
ContextStartedEvent ConfigurableApplicationContext ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。启动定时任务、启动异步消息处理 等
ContextStoppedEventConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。可在接受到这个事件后做必要的清理工作停止定时任务、关闭数据库等
ContextClosedEventConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。适用于在应用程序关闭前执行最后的清理工作释放资源、保存日志等
RequestHandledEvent web-specific 事件,告诉所有 bean HTTP 请求已经被服务处理。只能应用于使用DispatcherServletWeb应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件记录请求日志、处理统计数据等

代码示例

@Slf4j
@Component
public class ApplicationConfig implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        log.info("{} 服务初始化完成!!!", this.applicationContext.getApplicationName());
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) {
            String contextName = event.getApplicationContext().getDisplayName();
            String applicationName = event.getApplicationContext().getApplicationName();
            log.info("ApplicationContext  is  success  refreshed,contextName:{},applicationName:{}", contextName, applicationName);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值