理解 Spring 应用上下文生命周期

简介: 前言Spring 应用上下文(ApplicationContext),是 Spring 应用的核心接口,也是我们常说的 Spring 容器,除了扩展了基础容器 BeanFactory 还提供了更多企业级的特性,如资源管理、事件发布、国际化等。

前言


Spring 应用上下文(ApplicationContext),是 Spring 应用的核心接口,也是我们常说的 Spring 容器,除了扩展了基础容器 BeanFactory 还提供了更多企业级的特性,如资源管理、事件发布、国际化等。理解 Spring 应用上下文的生命周期也就理解了 Spring 内部的运行的核心逻辑,生命周期中同时提供了很多扩展点,跟随文章,我们一探究竟。


应用上下文的生命周期


Spring ApplicationContext 具有层次性的设计,生命周期的管理主要在 AbstractApplicationContext,类图如下。


image.png


生命周期的相关方法均由实现的接口提供,各生命周期阶段并非完整的从上而下执行,部分阶段是可选的,具体如下。


刷新阶段:org.springframework.context.ConfigurableApplicationContext#refresh

启动阶段:org.springframework.context.Lifecycle#start

停止阶段:org.springframework.context.Lifecycle#stop

关闭阶段:org.springframework.context.ConfigurableApplicationContext#close


刷新阶段


刷新阶段是 Spring 应用上下文生命周期的主要阶段,刷新阶段完成后 Spring 中的非延迟单例 bean 即实例化完成,依赖注入也完成,可以正常调用 bean 的方法。有关 bean 的生命周期可参考我前面的文章《Java 面试必备的 Spring Bean 生命周期总结》。


刷新阶段对应的 AbstractApplicationContext#refresh 方法源码如下。


  @Override
  public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      // 应用上下文刷新准备
      prepareRefresh();
      // BeanFactory 创建
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // BeanFactory 准备
      prepareBeanFactory(beanFactory);
      try {
        // BeanFactory 后处理,由子类扩展
        postProcessBeanFactory(beanFactory);
        // BeanFactory 后处理,调用 BeanFactoryPostProcessor 方法
        invokeBeanFactoryPostProcessors(beanFactory);
        // 注册 BeanPostProcessor
        registerBeanPostProcessors(beanFactory);
        // 初始化 MessageSource
        initMessageSource();
        // 初始化事件广播器
        initApplicationEventMulticaster();
        // 上下文刷新
        onRefresh();
        // 注册事件监听器
        registerListeners();
        // 初始化完成,实例化所有非延迟初始化的单例 bean
        finishBeanFactoryInitialization(beanFactory);
        // 刷新完成
        finishRefresh();
      } catch (BeansException ex) {
        destroyBeans();
        cancelRefresh(ex);
        throw ex;
      } finally {
        resetCommonCaches();
      }
    }
  }


下面对应用上下文的刷新阶段进行细化分析。


上下文刷新准备阶段


上下文刷新准备阶段的工作如下:


设置启动时间及状态标识。

初始化 PropertySource。

由子类进行扩展,web 环境下将初始化名称为 servletContextInitParams 和 servletConfigInitParams 的 PropertySource 。

关于 PropertySource 可参见我前面的文章《Spring 中的 Environment 、Profile 与 PropertySource》。

校验 Environment 中必须的属性。

初始化事件监听器集合。

关于 Spring 事件可参见我前面的文章《Spring 事件处理机制详解,带你吃透 Spring 事件》 。

初始化早期事件集合。

对应的AbstractApplicationContext#prepareRefresh方法源码如下。


  protected void prepareRefresh() {
    // 设置刷新事件及激活状态
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);
    ... 省略日志打印代码
    // 初始化 Environment 中的 PropertySource,该方法为空方法,由子类实现,如 web 环境下添加 ServletContext 初始化及 Servlet 配置的 PropertySource
    initPropertySources();
    // 校验 Environment 设置的必须的属性
    getEnvironment().validateRequiredProperties();
    if (this.earlyApplicationListeners == null) {
      // 首次 fresh,把刷新前添加的监听器添加到 earlyApplicationListeners
      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
    } else {
      // 再次 fresh,把之前添加的监听器添加到 applicationListeners
      this.applicationListeners.clear();
      this.applicationListeners.addAll(this.earlyApplicationListeners);
    }
    // 初始化事件集合,事件广播器初始化完成后发布
    this.earlyApplicationEvents = new LinkedHashSet<>();
  }


BeanFactory 创建阶段


BeanFactory 创建阶段的工作如下:


刷新 BeanFactory。

销毁并关闭 BeanFactory,如果已存在。

创建 BeanFactory。

设置 BeanFactory 的 ID。

设置 BeanFactory 是否允许 BeanDefinition 重复注册及循环引用。

关于循环引用,可参见我前面的文章《Spring 循环依赖处理》。

加载 BeanDefinition。

抽象方法,由子类进行实现。XML 和注解方式加载 BeanDefinition 的方式有所不同。

关于 BeanDefinition,可参见我前面的文章《掌握 Spring 必须知道的 BeanDefinition》 。

关联 BeanFactory 到应用上下文。

获取 BeanFactory。

相关的源码说明如下所示。


  // AbstractApplicationContext#obtainFreshBeanFactory
  protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 先创建 BeanFactory,该方法为抽象方法,由子类进行实现
    refreshBeanFactory();
    // 再获取 BeanFactory
    return getBeanFactory();
  }
  // AbstractRefreshableApplicationContext#refreshBeanFactory
  @Override
  protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
      // 如果已经存在 BeanFactory,先销毁 bean ,然后关闭 BeanFactory
      destroyBeans();
      closeBeanFactory();
    }
    try {
      // 创建 BeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      // 设置是否允许重复注册 BeanDefinition,是否允许循环引用
      customizeBeanFactory(beanFactory);
      // 加载 BeanDefinition,抽象方法,由子类进行实现
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
        this.beanFactory = beanFactory;
      }
    } catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
  }


BeanFactory 准备阶段


BeanFactory 准备阶段的工作如下:


设置加载 bean class 的 ClassLoader。

设置解析 BeanDefinition 中字符串的表达式处理器。

添加 PropertyEditorRegistrar 的实现 ResourceEditorRegistrar。

添加 Aware 回调接口 BeanPostProcessor 的实现 ApplicationContextAwareProcessor。

支持的 Aware 回调接口包括 EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware。

忽略 Aware 回调接口作为依赖注入接口。

忽略的 Aware 回调接口和上面 ApplicationContextAwareProcessor 支持的 Aware 回调接口相对应,保持一致。

注册 ResolvableDependency 对象作为 bean。

包括 BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。

添加 BeanPostProcessor 的实现 ApplicationListenerDetector。用于将 ApplicationListener 添加到 ApplicationContext。

如果 BeanFactory 中存在名称为 loadTimeWeaver 的 bean,

添加 BeanPostProcessor 的实现 LoadTimeWeaverAwareProcessor。

设置临时类加载器 ContextTypeMatchClassLoader。

注册单例 bean Environment、Java System Properties、OS 环境变量。

相关的源码说明如下所示:


  // AbstractApplicationContext#prepareBeanFactory
  protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 设置类加载器、表达式处理器;添加 ResourceEditorRegistrar
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    // 配置 Aware 回调接口的处理器 ApplicationContextAwareProcessor,并且忽略依赖注入对应的 Aware 接口
    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.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    // 添加 ApplicationListenerDetector,用于添加事件监听器到应用上下文
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    // AOP 相关
    if (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()));
    }
    // 注册默认的环境相关的单例 bean
    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());
    }
  }


BeanFactory 后置处理阶段


BeanFactory 后置处理阶段的工作如下:


调用方法 postProcessBeanFactory。

该方法实现为空,由子类进行扩展。

如 web 环境下会设置 ServletContextAware、ServletConfigAware 回调处理,注册 web 环境下的 scope 及相关的 bean。

调用 BeanFactoryPostProcessor 中的后置处理方法。

如果临时 ClassLoader 不存在并且存在名称为 loadTimeWeaver 的 bean,

添加 BeanPostProcessor 的实现 LoadTimeWeaverAwareProcessor。

设置临时类加载器 ContextTypeMatchClassLoader。

相关的源码如下:


  // AbstractRefreshableWebApplicationContext#postProcessBeanFactory
  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 添加 web 环境下 aware 处理,忽略 aware 依赖注入接口
    beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
    // 注册 web 环境下的 scope
    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    // 注册 web 环境下的 bean
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
  }
  // AbstractApplicationContext#invokeBeanFactoryPostProcessors
  protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 调用 BeanFactoryPostProcessor 处理方法  
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    // AOP 相关
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
  }



BeanPostProcessor 注册阶段


BeanPostProcessor 注册阶段的工作主要是将 BeanPostProcessor 类型的 bean 添加到 BeanFactory 内部持有的 BeanPostProcessor 列表中。添加顺序如下:


实现 PriorityOrdered 接口的 BeanPostProcessor。

实现 Ordered 接口的 BeanPostProcessor。

普通的 BeanPostProcessor。

实现 MergedBeanDefinitionPostProcessor 接口的 BeanPostProcessor。

ApplicationListenerDetector 接口。

相关的源码如下:


  // AbstractApplicationContext#registerBeanPostProcessors
  protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
  }


MessageSource 初始化阶段


MessageSource 初始化阶段用于保证 BeanFactory 中存在 MessageSource 类型的单例 bean。关于 MessageSource,可参见我前面的文章《Spring 国际化支持之 MessageSource》。


相关的源码如下:


  protected void initMessageSource() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
      // 设置 messageSource 到当前应用上下文
      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
      // 设置父 MessageSource
      if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
        HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
        if (hms.getParentMessageSource() == null) {
          hms.setParentMessageSource(getInternalParentMessageSource());
        }
      }
    } else {
      // 设置 MessageSource 到当前应用上下文,通过调用父 MessageSource 实现其功能
      DelegatingMessageSource dms = new DelegatingMessageSource();
      dms.setParentMessageSource(getInternalParentMessageSource());
      this.messageSource = dms;
      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
    }
  }


事件广播器初始化阶段


事件广播器初始化阶段主要用来保证应用上下文中存在 ApplicationEventMulticaster。相关的源码如下:


  protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      // 存在名称为 applicationEventMulticaster 的 bean,设置到应用上下文
      this.applicationEventMulticaster =
          beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      }
    } else {
      // 不存在 bean,设置到当前应用上下文,并注册为 bean
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      }
    }
  }


上下文刷新阶段


上下文刷新阶段对应的方法为AbstractApplicationContext#onRefresh,该方法为空方法,由子类进行实现。


事件监听器注册阶段


事件监听器注册阶段的工作如下:


添加当前应用上下文关联的事件监听器到广播器。

添加 BeanFactory 中注册的事件监听器 bean 到广播器。

广播早期事件。

相关源代码如下:


  protected void registerListeners() {
    // 添加应用上下文中的事件监听器到事件广播器中
    for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
    }
    // 添加 BeanFactory 中注册的事件监听器到事件广播器中
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }
    // 发布早期事件
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
        // 广播当前应用上下文刷新前发布的事件
        getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
    }
  }


BeanFactory 初始化完成阶段


BeanFactory 初始化完成阶段的工作如下:


如果 BeanFactory 中存在注册的名称为 conversionService 的 ConversionService,将其设置到 BeanFactory 中。

如果 BeanFactory 中不存在 StringValueResolver,添加 StringValueResolver 到 BeanFactory。

依赖查找 LoadTimeWeaverAware 接口。

BeanFactory 置空临时类加载器。

BeanFactory 冻结配置。

BeanFactory 实例化非延迟单例 bean。

对应的源代码如下:


  // AbstractApplicationContext#finishBeanFactoryInitialization
  protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    // 初始化当前上下文的 ConversionService
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
        beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
          beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }
    // 添加 StringValueResolver
    if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }
    // 尽早初始化LoadTimeWeaverAware bean,以便尽早注册其转换器。
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
    }
    // 停止使用临时类加载器进行类型匹配。
    beanFactory.setTempClassLoader(null);
    // 允许缓存所有bean定义元数据,不需要进一步更改。
    beanFactory.freezeConfiguration();
    // 实例化所有剩余的(非延迟初始化)单例。
    beanFactory.preInstantiateSingletons();
  }


上下文刷新完成阶段


上下文刷新完成阶段的工作如下:


清除 ResourceLoader 缓存。

初始化 LifecycleProcessor 对象。

调用LifecycleProcessor#onRefresh方法。

发布上下文刷新事件。

向 MBeanServer 托管 Live Beans。

相关的源代码如下:


  protected void finishRefresh() {
    // 清空 ResourceLoader 缓存
    clearResourceCaches();
    // 初始化 LifecycleProcessor
    initLifecycleProcessor();
    // 调用刷新方法
    getLifecycleProcessor().onRefresh();
    // 发布上下文刷新事件
    publishEvent(new ContextRefreshedEvent(this));
    // 向 MBeanServer 托管 Live Beans
    LiveBeansView.registerApplicationContext(this);
  }


启动阶段


启动阶段的方法为AbstractApplicationContext#start,该方法的调用必须在#refresh方法之后。主要工作如下:

  • 调用LifecycleProcessor#start法。
  • 发布上下文启动事件。

对应的源代码如下。


  public void start() {
    // 需要先获取 LifecycleProcessor,因此必须等 #refresh 方法调用后才能调用该方法
    getLifecycleProcessor().start();
    publishEvent(new ContextStartedEvent(this));
  }


停止阶段


停止阶段和启动阶段相对应,也应在#refresh方法调用后调用。主要工作如下:

  • 调用LifecycleProcessor#stop方法。
  • 发布上下文关闭事件。

对应的源码如下。


  public void stop() {
    getLifecycleProcessor().stop();
    publishEvent(new ContextStoppedEvent(this));
  }


关闭阶段


Spring 应用上下文的启动和停止阶段均为可选的生命周期,而关闭阶段可以在停止使用应用上下文后调用。主要的工作如下:


设置上下文状态标识。

Live Beans 撤销 JMX 托管。

发布上下文关闭事件。

调用LifecycleProcessor#onClose关闭 Lifecycle。

销毁 BeanFactory 中的单例 bean。

关闭 BeanFactory。

回调#onClose方法,由子类实现。

移除注册的 JVM 关闭时的 shutdown hook。

相关的源代码如下。


  public void close() {
    synchronized (this.startupShutdownMonitor) {
      doClose();
      // 如果注册了 JVM shutdown hoo 则进行移除。
      if (this.shutdownHook != null) {
        try {
          Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
        } catch (IllegalStateException ex) {
          // ignore - VM is already shutting down
        }
      }
    }
  }
  protected void doClose() {
    // 检查是否需要关闭
    if (this.active.get() && this.closed.compareAndSet(false, true)) {
      // 撤销 JMX 托管
      LiveBeansView.unregisterApplicationContext(this);
      try {
        // 发布关闭事件
        publishEvent(new ContextClosedEvent(this));
      } catch (Throwable ex) {
        logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
      }
      // 停止所有的 Lifecycle bean
      if (this.lifecycleProcessor != null) {
        try {
          this.lifecycleProcessor.onClose();
        } catch (Throwable ex) {
          logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
        }
      }
      // 销毁 BeanFactory 中的所有单例 bean
      destroyBeans();
      // 关闭 BeanFactory
      closeBeanFactory();
      // 子类扩展的方法
      onClose();
      // 重置 applicationListeners
      if (this.earlyApplicationListeners != null) {
        this.applicationListeners.clear();
        this.applicationListeners.addAll(this.earlyApplicationListeners);
      }
      // 设置激活标识
      this.active.set(false);
    }
  }
目录
相关文章
|
25天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
97 62
|
23天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
23天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
40 2
|
1月前
|
人工智能 开发框架 Java
总计 30 万奖金,Spring AI Alibaba 应用框架挑战赛开赛
Spring AI Alibaba 应用框架挑战赛邀请广大开发者参与开源项目的共建,助力项目快速发展,掌握 AI 应用开发模式。大赛分为《支持 Spring AI Alibaba 应用可视化调试与追踪本地工具》和《基于 Flow 的 AI 编排机制设计与实现》两个赛道,总计 30 万奖金。
|
30天前
|
存储 Java 数据管理
强大!用 @Audited 注解增强 Spring Boot 应用,打造健壮的数据审计功能
本文深入介绍了如何在Spring Boot应用中使用`@Audited`注解和`spring-data-envers`实现数据审计功能,涵盖从添加依赖、配置实体类到查询审计数据的具体步骤,助力开发人员构建更加透明、合规的应用系统。
|
3月前
|
运维 Java Nacos
Spring Cloud应用框架:Nacos作为服务注册中心和配置中心
Spring Cloud应用框架:Nacos作为服务注册中心和配置中心
|
5月前
|
Java 应用服务中间件 Maven
ContextLoaderListener在Spring应用中的作用与配置方法
ContextLoaderListener在Spring应用中的作用与配置方法
|
Java 开发者 微服务
深入解析@SpringBootApplication注解:简化Spring Boot应用的配置
在现代的Java开发中,Spring Boot框架成为了构建微服务和快速开发应用的首选。Spring Boot的成功部分归功于其简化的配置和约定大于配置的理念。而`@SpringBootApplication`注解则是Spring Boot应用的入口,负责自动配置和启动Spring Boot应用。本文将深入探讨`@SpringBootApplication`注解的作用、用法,以及在Spring Boot应用中的应用场景。
1134 1
|
6月前
|
安全 Java Maven
Spring Boot常见企业开发场景应用、自动配置原理结构分析(三)
Spring Boot常见企业开发场景应用、自动配置原理结构分析
|
6月前
|
Java 数据库连接 Spring
Spring Boot常见企业开发场景应用、自动配置原理结构分析(二)
Spring Boot常见企业开发场景应用、自动配置原理结构分析
下一篇
无影云桌面