解析BeanDefinitionRegistry与BeanDefinition合并

本文分享自华为云社区《Spring高手之路12——BeanDefinitionRegistry与BeanDefinition合并解析》,作者:砖业洋__ 。

1.什么是BeanDefinitionRegistry?

BeanDefinitionRegistry 是一个非常重要的接口,存在于 Spring 的 org.springframework.beans.factory.support 包中,它是 Spring 中注册和管理 BeanDefinition 的核心组件。

在 Spring 中,一个 Bean 就是一个被 Spring 管理的对象,而一个 BeanDefinition 则是一个 Bean 的配置描述,它描述了一个 Bean 的数据。它包含了 Bean 的类名、是否为抽象类、构造函数和属性值等信息。这些元数据将指导 Spring 如何创建和初始化 Bean。

再来看一下 BeanDefinitionRegistry 的作用,BeanDefinitionRegistry 的主要职责就是注册和管理这些 BeanDefinition。我们可以把它看作是一个存放 BeanDefinition 的注册表,向其中注册新的 BeanDefinition,或者检索和删除现有的 BeanDefinition。它提供了一些方法,如 registerBeanDefinition(String, BeanDefinition), removeBeanDefinition(String),和 getBeanDefinition(String),用于执行这些操作。

在 Spring 的内部,BeanDefinitionRegistry 通常由 BeanFactory 实现,特别是 DefaultListableBeanFactory 和 GenericApplicationContext,它们都实现了这个接口。

2. 为什么需要BeanDefinitionRegistry?

如果BeanDefinitionRegistry不存在,Spring的某些核心功能会受到什么样的影响?

1.资源解析的统一性:BeanDefinition作为一个统一的数据结构存储了Bean的配置信息。如果没有BeanDefinitionRegistry,每种配置方式(XML、注解、Java配置)都需要各自的专门数据结构。这不仅会导致资源解析的代码复杂度增加,还可能在不同的解析机制之间产生不一致性。

2.依赖查找和注入:BeanDefinitionRegistry提供了一个中心位置,充当了Bean定义的中央存储,可以快速查找Bean的定义。如果没有它,当需要注入一个Bean的依赖时,Spring不仅需要遍历所有的配置源来查找对应的Bean,而且还可能遭遇Bean定义不一致的问题,这会显著降低性能和准确性。

Bean定义不一致的例子如下:

<!-- in config1.xml -->

<bean id="sampleBean" class="com.example.SampleBean1" />

<!-- in config2.xml -->

<bean id="sampleBean" class="com.example.SampleBean2" />

这里,sampleBean 在两个配置文件中都有定义,但它们引用了不同的类。如果没有BeanDefinitionRegistry集中处理这些定义,那么Spring在尝试初始化sampleBean时可能会遭遇混淆,比如Spring尝试创建ServiceA的实例并为它注入sampleBean时,就会出现一个问题:Spring应该选择哪一个sampleBean的定义?com.example.SampleBean1还是com.example.SampleBean2?

这就是所谓的“Bean定义不一致”问题。如果Spring不知道哪一个定义是正确的,那么它可能会注入错误的Bean,从而导致应用程序的行为出现问题或者失败。这也可能导致应用在运行时出现不可预测的错误,因为注入的Bean并不是应用期望的版本或类型。

通过使用BeanDefinitionRegistry,Spring可以在应用程序启动时检测这类问题,并在Bean定义冲突或不一致时提供明确的错误消息,而不是在运行时遭遇不确定的行为或错误。

3.延迟初始化和作用域管理:BeanDefinitionRegistry存储了Bean的作用域和其他元数据。如果没有这个BeanDefinitionRegistry,Spring在执行Bean的延迟加载或根据作用域创建Bean时,需要重新解析原始的配置资源,这增加了处理时间并可能导致潜在的配置错误。

4.配置验证:当所有BeanDefinition注册到BeanDefinitionRegistry后,Spring可以进行配置的校验,例如检查循环依赖、确保Bean定义的完整性等。如果没有BeanDefinitionRegistry,Spring需要在每次Bean初始化时进行检查,这不仅导致性能下降,还可能漏掉某些隐晦的配置问题。

5.生命周期管理:没有BeanDefinitionRegistry存储生命周期回调、初始化方法等信息,Spring在管理Bean的生命周期时,需要从原始的配置源获取这些信息。这不仅增加了管理的复杂度,还会使生命周期回调会变得复杂和笨重。

简而言之,没有BeanDefinitionRegistry,Spring会失去中心化的Bean管理,导致效率下降、错误处理分散、以及增加生命周期管理的复杂度。BeanDefinitionRegistry确保了Spring的高效、一致和稳定运行。

3. BeanDefinitionRegistry 的使用

3.1 BeanDefinitionRegistry 简单例子

在这个例子中,我们将创建一个简单的 Bean,注册到 DefaultListableBeanFactory(它实现了 BeanDefinitionRegistry 接口),然后从工厂中获取并使用这个 Bean。

全部代码如下:

首先,我们需要一个 Bean 类,这是一个简单的 POJO 类:

package com.example.demo.bean;

public class MyBean {

private String message;

public void doSomething() {

System.out.println("Hello, world!");

}

public void setMessage(String message){

this.message = message;

}

public void getMessage(){

System.out.println("Your Message : " + message);

}

}

然后,我们可以使用 DefaultListableBeanFactory 和 RootBeanDefinition 来创建并注册这个 Bean:

package com.example.demo;

import com.example.demo.bean.MyBean;

import org.springframework.beans.factory.config.BeanDefinition;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import org.springframework.beans.factory.support.RootBeanDefinition;

public class DemoApplication {

public static void main(String[] args) {

// 创建 BeanDefinitionRegistry

DefaultListableBeanFactory registry = new DefaultListableBeanFactory();

// 创建一个 BeanDefinition

BeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);

// 注册 BeanDefinition

registry.registerBeanDefinition("myBean", beanDefinition);

// 从 BeanFactory 中获取 Bean

MyBean myBean = registry.getBean("myBean", MyBean.class);

// 使用 Bean

myBean.doSomething(); // 输出:Hello, world!

}

}

这个程序会创建一个名为 "myBean" 的 Bean,这个 Bean 是 MyBean 类的一个实例。然后,我们从 BeanFactory 中获取这个 Bean,并调用其 doSomething 方法,打印 "Hello, world!"。

cke_142.png

3.2 有关ImportBeanDefinitionRegistrar的实现类的例子

这个在第8篇(Spring高手之路8——Spring Bean模块装配的艺术:@Import详解)提到过,是3.5节,大家可以回头看,这里不重复粘贴代码。

4. BeanDefinition的合并

我们前一篇讲解BeanDefinition的时候没有讲解BeanDefinition的合并,这里补充说明。

1.BeanDefinition

在 Spring 中,BeanDefinition 是一个接口,它定义了 Bean 的配置信息,例如 Bean 的类名,是否是单例,依赖关系等。在 Spring 中,每一个 Bean 都对应一个 BeanDefinition 对象。

2.合并的意义

在 Spring 中,有一种特殊的 BeanDefinition,叫做子 BeanDefinition,也就是我们在 XML 配置文件中通过 parent 属性指定的那种。这种子 BeanDefinition 可以继承父 BeanDefinition 的配置信息。

合并的过程,就是把子 BeanDefinition 的配置信息和父 BeanDefinition 的配置信息合并起来,形成一个完整的配置信息。合并后的 BeanDefinition 对象包含了 Bean 创建所需要的所有信息,Spring 将使用这个完整的 BeanDefinition 来创建 Bean 实例。

3.合并的过程

Spring 在需要创建 Bean 实例的时候,会先获取对应的 BeanDefinition 对象。如果这个 BeanDefinition 是一个子 BeanDefinition,Spring 就会找到它的父 BeanDefinition,然后把两者的配置信息合并起来,形成一个完整的 BeanDefinition。

这个过程是在 DefaultListableBeanFactory 的 getMergedBeanDefinition 方法中进行的,如果大家有兴趣,可以在这个方法中设置断点,看一看具体的合并过程。

4.合并过程的流程图

cke_143.png

我们可以通过父子Bean的方式使用这个特性,下面是一个XML配置的例子:

<bean id="parentBean" class="com.example.ParentClass" abstract="true">

<property name="commonProperty" value="commonValue" />

</bean>

<bean id="childBean" parent="parentBean">

<property name="specificProperty" value="specificValue" />

</bean>

在这个例子中,我们定义了两个bean,一个是 parentBean,另一个是 childBean。parentBean 是 abstract 的,表示它不会被实例化,只作为模板使用。childBean 的 parent 属性指向 parentBean,表示它继承了 parentBean 的配置。

parentBean 有一个属性 commonProperty,值为 commonValue。childBean 有一个属性 specificProperty,值为 specificValue。在Spring解析这个配置文件,生成BeanDefinition的时候,childBean 的BeanDefinition会包含两个属性:commonProperty 和 specificProperty,这就是 BeanDefinition 的合并过程。

在Java配置中,我们无法直接模拟XML配置的BeanDefinition合并过程,因为这是Spring XML配置的一项特性,配置类通常会采用Java代码的继承或组合来重用bean定义,不会涉及到配置元数据层面的BeanDefinition合并。XML配置中的BeanDefinition合并特性允许我们定义一个父Bean,然后定义一些子Bean,子Bean可以继承父Bean的一些属性。

这个特性在Java配置中并没有直接的替代品,因为Java配置通常更加依赖实例化过程中的逻辑,而不是元数据(即BeanDefinition)。在Java配置中,我们可以使用继承和组合等普通的Java特性来实现类似的结果,但这不是真正的BeanDefinition合并。因此,当我们从XML配置转换为Java配置时,通常需要手动将共享的属性复制到每个Bean的定义中。

4.1 调试验证BeanDefinition的合并

全部代码如下:

首先,创建 XML 配置文件 applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="parentBean" class="com.example.demo.bean.ParentClass" abstract="true">

<property name="commonProperty" value="commonValue" />

</bean>

<bean id="childBean" parent="parentBean" class="com.example.demo.bean.ChildClass">

<property name="specificProperty" value="specificValue" />

</bean>

</beans>

然后,创建 ParentClass 和 ChildClass,如下:

package com.example.demo.bean;

public abstract class ParentClass {

private String commonProperty;

public String getCommonProperty() {

return commonProperty;

}

public void setCommonProperty(String commonProperty) {

this.commonProperty = commonProperty;

}

}

package com.example.demo.bean;

public class ChildClass extends ParentClass {

private String specificProperty;

public String getSpecificProperty() {

return specificProperty;

}

public void setSpecificProperty(String specificProperty) {

this.specificProperty = specificProperty;

}

}

主程序如下:

package com.example.demo;

import org.springframework.beans.factory.config.BeanDefinition;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoApplication {

public static void main(String[] args) {

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();

// 获取childBean的原始BeanDefinition

BeanDefinition childBeanDefinition = factory.getBeanDefinition("childBean");

System.out.println("Child bean definition before merge: " + childBeanDefinition);

// 获取合并后的BeanDefinition

BeanDefinition mergedBeanDefinition = factory.getMergedBeanDefinition("childBean");

System.out.println("Merged bean definition: " + mergedBeanDefinition);

}

}

在这个示例中,我们首先加载了 applicationContext.xml 配置文件,然后获取了 childBean 的原始 BeanDefinition。然后,我们调用 getMergedBeanDefinition 方法获取了合并后的 BeanDefinition,可以在这个过程中设置断点来查看合并过程的详细情况。

运行结果:

cke_144.png

大家可以从运行结果看到打印了Generic bean和Root bean,代表了GenericBeanDefinition 和 RootBeanDefinition。

为什么有两个不同的 BeanDefinition 类型( GenericBeanDefinition 和 RootBeanDefinition)?

GenericBeanDefinition:

  • 这是一个通用的BeanDefinition实现类,可以配置任何类型的bean。
  • 它通常用于读取XML、注解或其他形式的配置。
  • 与其它特定的BeanDefinition相比,它是比较简单和轻量级的。
  • 当使用<bean>元素在XML中定义bean时,通常会为该bean创建一个GenericBeanDefinition实例。

RootBeanDefinition:

  • 这是一个完整的bean定义,包含了bean的所有配置信息,如构造函数参数、属性值、方法覆盖等。
  • 它通常用于合并父子bean定义。也就是说,当一个bean定义继承另一个bean定义时,RootBeanDefinition负责持有合并后的最终配置。
  • 除了GenericBeanDefinition之外,它还包含许多与bean的实例化、依赖解析和初始化相关的内部细节。
  • 在Spring的内部工作流中,尽管开始时可以有各种BeanDefinition实现,但在容器的后期处理阶段,它们通常都会转化为RootBeanDefinition,因为在这个阶段需要一个完整和固定的bean定义来进行bean的创建。

调试点1:我们从BeanFactory中获取了子bean的原始BeanDefinition。这个BeanDefinition只表示了XML中为子bean配置的元数据,没有与父Bean的合并,只能看到specificProperty属性。

cke_145.png

调试点2:用getMergedBeanDefinition之后,控制台打印的 BeanDefinition 的类型变为了 RootBeanDefinition ,此时,我们从BeanFactory中获取了合并后的子Bean的BeanDefinition。由于子Bean的BeanDefinition与父Bean的BeanDefinition已合并,所以能看到一个完整的属性集,这里在propertyValues中看到两个属性键值对:commonProperty和specificProperty,这表明子Bean继承了父Bean的属性值。

cke_146.png

注意,这个示例的目的是展示 BeanDefinition 的合并过程,因此我们直接操作了 BeanFactory。在实际的应用开发中,我们一般不会直接操作 BeanFactory。

4.2 BeanDefinition合并的目的

  1. 提供完整的BeanDefinition信息:在配置中,我们经常会使用父子BeanDefinition(如通过<bean>标签的parent属性)。子BeanDefinition可能只会定义需要改变或增加的bean属性,而父BeanDefinition则提供共享的默认定义。在这种情况下,合并操作会将父子BeanDefinition的信息合并为一个完整的BeanDefinition,用于接下来的bean创建。
  2. 优化性能:合并操作的结果通常会被缓存起来,因此在下次获取同样的bean时,可以直接从缓存中获取合并后的BeanDefinition,避免了重复的合并操作,从而提高了性能。
  3. 解决循环依赖:在处理bean之间的循环依赖时,需要尽早抛出已经处理(例如实例化和属性填充)的bean,这时就需要一个完整的BeanDefinition信息。因此,BeanDefinition的合并在解决循环依赖问题上也有重要作用。

简而言之,BeanDefinition的合并是为了得到一个完整、准确的BeanDefinition,以供Spring IoC容器后续的bean创建和依赖解析使用。

4.3 图解BeanDefinition合并与Spring初始化关系

cke_147.png

1.资源定位

在此阶段,Spring会根据用户的配置来确定需要加载的资源位置,资源可能来源于多种配置方式,如XML、Java注解或Java配置。

2.读取配置

Spring从确定的配置源中读取Bean定义信息

  • 对于XML配置,解析器会处理每一个<bean>元素。在这个时候,特别是存在父子Bean关系的定义,这些定义被解析为原始的BeanDefinition,但并没有合并。
  • 对于注解和Java配置,BeanDefinition被解析为独立的定义,通常不涉及父子关系。

3.注册BeanDefinition

Spring会将所有解析得到的BeanDefinition注册到BeanDefinitionRegistry中。

4.处理BeanDefinition

在这个阶段,Spring进行BeanDefinition的预处理。

  • 如果从XML配置中读取的Bean之间存在父子关系,这时会进行合并,合并后的BeanDefinition确保子Bean继承了父Bean的所有属性,并且能够覆盖它们。
  • 而基于注解或Java配置的Bean定义,由于没有明确的父子关系,这种合并操作通常不会发生。

5.Bean的实例化与属性填充

  • 此阶段标志着Spring生命周期的开始。
  • 所有的BeanDefinition,无论是原始的还是经过合并的,都会在此阶段转化为实际的Bean实例。
  • Spring容器将负责管理这些Bean的完整生命周期,包括但不限于依赖注入、属性设置。

6.Bean的初始化

  • 包括调用Bean的初始化方法,例如实现了InitializingBean接口的afterPropertiesSet方法或者通过init-method属性指定的自定义初始化方法。
  • 在此阶段,Bean已经完全准备好,可以供应用程序使用。

7.注册Bean的销毁方法

  • Spring会跟踪并注册Bean的销毁方法。
  • 这确保了当Spring容器关闭时,它会正确地调用每个Bean的销毁方法,例如实现了DisposableBean接口的destroy方法或通过destroy-method属性指定的自定义方法。

从这里可以看到BeanDefinition的合并发生在实际Bean实例化之前的早期阶段,这确保了当Spring去创建一个Bean实例时,它有一个完整的、合并的定义可以依赖。

5. BeanDefinition的合并的源码分析

5.1 BeanDefinition合并过程时序图

cke_148.png

5.2 BeanDefinition合并过程源码解读

这里讲一下前一篇没提到的BeanDefinition的合并,我们针对Spring 5.3.7的源码分析一下,先展示图,后面分析。

cke_149.png

我们分析一下AbstractBeanFactory类的几个方法。

// 获取本地合并后的 BeanDefinition

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {

// 从缓存中获取合并后的 BeanDefinition

RootBeanDefinition mbd = (RootBeanDefinition)this.mergedBeanDefinitions.get(beanName);

// 如果缓存中的 BeanDefinition 不为空并且未过时,则直接返回

// 否则,对 BeanDefinition 进行合并

return mbd != null && !mbd.stale ? mbd : this.getMergedBeanDefinition(beanName, this.getBeanDefinition(beanName));

}

// 获取合并后的 BeanDefinition

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) throws BeanDefinitionStoreException {

// 直接调用 getMergedBeanDefinition 方法,将 containingBd 设为 null

return this.getMergedBeanDefinition(beanName, bd, (BeanDefinition)null);

}

// 获取合并后的 BeanDefinition

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException {

synchronized(this.mergedBeanDefinitions) {

RootBeanDefinition mbd = null;

RootBeanDefinition previous = null;

// 如果没有包含的 BeanDefinition,那么从缓存中获取合并后的 BeanDefinition

if (containingBd == null) {

mbd = (RootBeanDefinition)this.mergedBeanDefinitions.get(beanName);

}

// 如果缓存中的 BeanDefinition 为空或者过时,那么创建新的 BeanDefinition 进行合并

if (mbd == null || mbd.stale) {

previous = mbd;

// 如果 bd 没有父名称,即没有继承其他的 bean

// 那么就直接 clone 这个 bd,生成一个 RootBeanDefinition

if (bd.getParentName() == null) {

if (bd instanceof RootBeanDefinition) {

mbd = ((RootBeanDefinition)bd).cloneBeanDefinition();

} else {

mbd = new RootBeanDefinition(bd);

}

} else { // 如果 bd 是一个子 BeanDefinition(即有父 BeanDefinition)

// 首先获取父 BeanDefinition

BeanDefinition pbd;

try {

String parentBeanName = this.transformedBeanName(bd.getParentName());

if (!beanName.equals(parentBeanName)) {

pbd = this.getMergedBeanDefinition(parentBeanName);

} else {

BeanFactory parent = this.getParentBeanFactory();

if (!(parent instanceof ConfigurableBeanFactory)) {

throw new NoSuchBeanDefinitionException(parentBeanName, "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + "': cannot be resolved without a ConfigurableBeanFactory parent");

}

pbd = ((ConfigurableBeanFactory)parent).getMergedBeanDefinition(parentBeanName);

}

} catch (NoSuchBeanDefinitionException var11) {

throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'", var11);

}

// 创建一个新的 RootBeanDefinition 并覆盖 bd 中的属性

// 这就完成了父子 BeanDefinition 的合并

mbd = new RootBeanDefinition(pbd);

mbd.overrideFrom(bd);

}

// 如果合并后的 BeanDefinition 没有指定作用域

// 则默认设置为 singleton

if (!StringUtils.hasLength(mbd.getScope())) {

mbd.setScope("singleton");

}

// 如果定义了父 BeanDefinition 且父 BeanDefinition 的作用域不是 singleton 但子 BeanDefinition 的作用域是 singleton

// 则将子 BeanDefinition 的作用域设置为父 BeanDefinition 的作用域

if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {

mbd.setScope(containingBd.getScope());

}

// 如果不存在包含的 BeanDefinition 并且需要缓存 BeanMetadata

// 那么就将这个新创建并合并的 BeanDefinition 放入 mergedBeanDefinitions 缓存中

if (containingBd == null && this.isCacheBeanMetadata()) {

this.mergedBeanDefinitions.put(beanName, mbd);

}

}

// 如果之前存在过期的 BeanDefinition

// 那么从过期的 BeanDefinition 中拷贝相关的缓存到新的 BeanDefinition 中

if (previous != null) {

this.copyRelevantMergedBeanDefinitionCaches(previous, mbd);

}

// 返回合并后的 BeanDefinition

return mbd;

}

}

这段代码主要完成了 BeanDefinition 的合并工作。当一个 BeanDefinition 有父 BeanDefinition 时,Spring 会将子 BeanDefinition 的定义与父 BeanDefinition 的定义进行合并,生成一个新的完整的 BeanDefinition,这个过程就是 BeanDefinition 的合并。该合并的 BeanDefinition 会被缓存起来,以便下次使用。如果一个 BeanDefinition 没有父 BeanDefinition,则直接 clone 一份作为合并后的 BeanDefinition。在 Spring 的整个生命周期中,BeanDefinition 的合并可能会发生多次,每次获取 Bean 时,都会先进行 BeanDefinition 的合并。

点击关注,第一时间了解华为云新鲜技术~

相关推荐

鸿蒙案例上新啦 | 购物、听歌、健身:15个模板带你一键激活社交娱乐

页面层级如何组织、跨页共享状态如何同步、列表与详情及个人中心如何形成稳定闭环。鸿蒙开发实践中心将这些高频消费与互动场景沉淀为可参考的标准模板,提供从业务架构到界面实现的快捷实践入口。更多实战案例欢迎前往鸿蒙开发实践中心案例中心查看并开启云端体验。

华为云官方博客 336

鸿蒙案例上新啦 | 出门打车、到家上课:25个模板带你一屏打通日常生活

如何合理拆分页面组件、如何建立单一可信的状态源、如何让用户在每一步操作中都获得明确反馈。鸿蒙开发实践中心以标准化的应用与元服务模板为入口,将清晰的业务架构与可复用的代码结构直观呈现。不妨立即挑选一个感兴趣的方向进入云端环境,从页面布局、组件封装、状态管理到路由组织,亲手跑通你的鸿蒙实战项目。

华为云官方博客 323

LakeAgent:DWS数据仓库的第二大脑,告别 “翻译式运维”,迈入智能自治时代

和普通 SQL 改写工具不同,LakeAgent 自动做多方案代价对比,主动规避负优化陷阱:补充分区键过滤实现剪枝,扫描分区由 37 收敛至 1,执行代价从 758.28 降至 113.74;未来的数据仓库,将不止能算、能存,更能看懂自己、诊断自己、理解自己。长久以来,数仓的智能都依附于人:信号需要人解读,瓶颈需要人研判,经验困在个体里,无法随底座永续生长。CPU 高、CPU 告警、CPU 诊断、CPU 使用率过高、CPU 满。语法、错误码、计费、性能调优、最佳实践、故障处置等全场景内容。

华为云官方博客 554

如何使用RDS Supabase后端BaaS能力:文件存储(File Storage)

• product-images(公开桶,允许公共读取):策略名称"Public read for product-images",允许SELECT,目标角色anon,策略定义bucket_id = 'product-images'。上传/删除需另配INSERT/DELETE策略,详见SQL。• product-specs(私有桶,仅认证用户访问自己的文件夹):建议拆为上传、读取、删除三条策略,策略定义均为 bucket_id = 'product-specs' 且仅限本人文件夹(详见下文 SQL)。

华为云官方博客 474

如何使用RDS Supabase后端BaaS能力:实时订阅与推送(Realtime)

Realtime 把数据库的每次变更同步到客户端:表里增、删、改一行,订阅者无需刷新页面或主动请求即可秒级收到。三大能力各司其职:• Postgres Changes — 监听表的 INSERT/UPDATE/DELETE,变化即通知• Broadcast — 客户端之间直接互发,适合瞬时通知、协同编辑• Presence — 跟踪频道里“谁在线”典型场景有实时数据展示(订单、库存、监控指标即时刷新)、即时通讯(消息收发、在线名单、“对方正在输入”)、协同编辑与实时通知。

华为云官方博客 464

AI Agent如何通过MCP连接到华为云RDS Supabase应用平台

Schema元数据列出所有可访问的表(按schema分组)。Schema元数据列出表的列及元数据(类型/默认值/约束)。Schema元数据列出所有约束(PK/FK/UNIQUE/CHECK/EXCLUDE)。可按schema/表/类型过滤。Schema元数据列出所有外键关系。可按schema/表过滤。Schema元数据列出所有索引及定义和大小。可按schema/表过滤。Schema元数据列出已应用的数据库迁移记录。Schema元数据列出已安装的PostgreSQL扩展。

华为云官方博客 472

华为大数据Flink让每一 CU 算力,跑出开源 5.74 倍的性能

1. 开源Apache Flink 已成为业界流计算事实标准,但在极端重负载场景下存在性能瓶颈。2. 华为大数据Flink通过多项自研深度优化,在执行计划、算子执行、状态存储三个层面构建协同的优化体系。3. Nexmark Benchmark 测试结果:整体性能提升 5.74 倍,极端重负载场景性能领先最高 18.3 倍。4. 100% 兼容 Apache Flink 1.20,业务代码零改造,无缝迁移。

华为云官方博客 379

LakeAgent实战 | 业务分析篇从一句提问到业务分析

本文以“订单金额变化”分析为例,展示LakeAgent如何通过自然语言提问,结合DataArtsStudio的数据资产与专业技能,帮助业务人员快速定位数据、生成SQL、追踪血缘、生成报告。从问题出发,逐步实现数据发现、变化洞察、原因追溯与团队协作,最终形成可复用的分析流程与企业规则,显著提升数据分析效率与一致性。

华为云官方博客 389

华为云RDS Supabase AI应用已开放公测 :30分钟搭建AI应用后端

认证、存储、实时推送、数据库API——4个后端模块,传统开发需要数周。今天,你只需要30分钟。AI创业公司的全栈开发工程师。上周老板说"下周要上线的AI对话应用,后端你来搞"——认证鉴权、数据库接口、文件存储、实时推送,每一个模块都需要数周搭建,而市场不会等你。小张打开华为云RDS Supabase,30分钟搭好认证、数据库API、对象存储,剩下的时间全用来打磨AI交互体验。基于开源Supabase+华为云RDS PostgreSQL全托管能力,为开发者提供。

华为云官方博客 396

如何使用RDS Supabase后端BaaS能力:数据库函数(Database Function)

上一篇介绍了 Database Data API——建表即自动生成增删改查接口,解决单表读写,但聚合统计、跨表事务、字段自动维护等逻辑已超出其能力边界。本篇推进到数据库函数(Database Function):把业务逻辑封装进数据库,前端通过 .rpc() 调用,由触发器自动响应数据变更。上一篇中,小张基于 Data API 完成了产品目录的建表与基础读写。但新需求随之而来:按分类统计产品数与价格区间、上架新品同时写产品表与定价表、产品修改后自动刷新更新时间。

华为云官方博客 463

如何使用RDS Supabase后端BaaS能力:创表即生成API(Database Data API)

认证、存储、实时推送、数据库API——4个后端模块,传统开发要数周。本系列逐个拆解,首篇聚焦数据库API(Database Data API):建表即得 API,无需手写后端。小张,AI创业公司的全栈工程师。老板让他做个产品目录页,展示产品与价格、支持上下架。传统做法要搭后端、写接口、配权限,工期少说1-2周;而在华为云RDS Supabase,建两张表、应用 SDK 直连,几分钟增删改查全跑通。

华为云官方博客 478

从一句话到一个能出去的链接,AI开发者空间做了什么

自行搭建的 Agent、正在使用的开源项目、团队既有的工具,都可以接入,可以通过AI创建或者手动搭建环境;华为云 AI开发者空间——面向开发者的云端一站式开发平台,做的就是把这段路接上:环境免安装,浏览器打开即为完整的 Linux 运行环境,预置的 AI 智能体开箱即用。第一个任务建议选能出结果的:做一个游戏、生成一个页面、创建一台实例,从需求走到可访问的链接,一次就能看清这个环境在做什么。沙箱是一个完整的 Linux 环境,依赖、服务、端口都是真实的,不是模拟。环境释放后,权限随之失效。

华为云官方博客 425

华为云码道配置自定义大模型,四种方式完整实操

案例介绍。

华为云官方博客 623

图数据库:实现穿透式监管的数据基座

穿透式监管标志着国企监管从“管企业”向“管资本”转型过程中的关键一跃。而图数据库正是这一跃的技术支点。从股权穿透到资金链穿透,从供应链穿透到数据穿透,华为GES图数据库正在将“穿透式监管”从理念变为可落地、可操作的实践。无论是天眼查式的全量链路查询,还是某集团财经的税务规则判断,抑或是芯片供应链式的部件风险分析,乃至通过Palantir构建决策知识图谱,其底层逻辑都是一致的——用图的力量,穿透一切形式的“隔离层”,直抵风险本质与责任核心。

华为云官方博客 664

《公共云三十问》正式收官,奔赴企业AI百场景新征程

今年6月底,公共云产业联盟重点推出《公共云三十问》专栏,以每周三问的节奏,连载十周,解读《先进公共云》白皮书,分享国计民生系列案例,旨在凝聚共识、推动落地实践。同时,专栏分析公共云在产业升级、民生福祉、科技创新、全球发展等方面的作用,梳理中国特色公共云发展路径:以普惠云拓展用云广度,以智算云提升用云深度,以自主云夯实用云厚度,以全球云打开用云跨度。这十问从专属云、行业云切入,深入政务、金融、交通、电力、钢铁、化工、油气、制造等国计民生场景,回答公共云“怎么用”。

华为云官方博客 473

开发者小技巧|IAM配置,让码道代码智能体连续30天免登录

案例介绍。

华为云官方博客 645

码道深度对接CodeArts,让需求自动落地为代码

案例介绍。

华为云官方博客 719

【公共云三十问 之三十】拥抱AI,企业如何建设面向智能体的专属云?

企业可分阶段建设覆盖开发、运行、运营及安全的一体化智能体平台——从构建一站式、高低码协同的智能体开发平台,到打造高性能、极致弹性的运行时环境,再到搭建AgentOps驱动的持续运营与运维体系,同时构建端到端、多层次的全链路安全防护体系。在数据湖建设方面,遵循“存量复用、平滑演进、AI导向、分步迭代”原则,分三阶段推进——打造AI多模数据湖核心能力、完成存算分离与统一元数据管理、实现闭环赋能全面支撑智能体规模化落地,在保护既有投资的前提下将传统数据平台转型为AI数据专属供给平台。

华为云官方博客 823

【公共云三十问 之二十九】国计民生之制造:制造云如何重塑数智时代的新质生产力?

平台打通软件交付的完整路径,覆盖需求管理、代码托管、代码检查、编译构建、制品仓库、部署、测试等关键环节,支持大模型能力融入研发全流程,实现从需求到交付的端到端管理。通过构建“研发一朵云”,方案打破地域与组织壁垒,实现跨团队协同开发,有效缩短软件交付周期,助力工业制造企业从“传统研发”走向“敏捷研发”,加速数智化转型进程。当制造云真正成为数据流通的平台、AI创新的底座,公共云的社会价值将从基础设施层向生产场景层持续延伸,为新型工业化建设和制造强国战略注入源源不断的动力,重塑数智时代的中国制造新质生产力。

华为云官方博客 789

告别重复手工迁仓,码道MCP+Skill实现仓库批量迁移

案例介绍。

华为云官方博客 790

【公共云三十问 之二十八】国计民生之油气:智算云如何叩响数智时代的“地心蓝金”?

西南油气田以“向地球深部要资源”为战略方向,联合以华为云Stack为代表的公共云服务商共同打造统一算力底座,建设西南区域数据湖与通用技术平台,构建“勘探开发工程技术、天然气生产过程管控、天然气产运储销”等三个一体化协同应用场景,支撑油气勘探、开发生产、管输储运等全业务链的数智化转型。当智算云真正成为数据流通的平台、AI创新的底座,油气田得以将算力效能、数据价值与智能技术深度融入勘探开发全链条,将“看不见的算力”转化为“摸得着的储量”,以智能化手段持续降低勘探风险、缩短发现周期、提高采收效率,确保生产安全。

华为云官方博客 613

【公共云三十问 之二十七】国计民生之化工:数智云如何重塑传统化工新范式?

在架构方面,方案构建云边协同的统一体系,涵盖AI协同、数据协同与运营协同三大维度——总部集中训练大模型,边缘节点负责推理执行,云边持续迭代,实现“边用边学”的智能闭环,模型平均精度提升20%以上。此外,方案提供一站式企业级工业物联网平台、数据湖与数据治理平台,覆盖工业数据分析“采、存、算、管、用”全流程,打通生产现场与管理系统间的数据壁垒,有效消除数据孤岛。层面,方案充分发挥软硬协同优势,实现计算、存储、网络与云平台的深度协同,训练线性度超95%,为大模型训练推理提供强劲算力支撑。▲化工“数智”新模式。

华为云官方博客 663

【公共云三十问 之二十六】国计民生之钢铁:数智云如何淬炼中国钢铁新力量?

同时,构建云边端协同的统一架构,支撑集团总部与各生产基地两级协同发展——总部集中训练大模型,边缘节点负责推理执行,云边持续迭代,实现训推一体化的资源调度与高效协同,为钢铁行业的数智化转型构建了坚实的算力底座。层面,方案构建覆盖“工业数采→边缘IT/OT融合→统一数据湖→数据治理平台→数据应用”全链路的一站式数据治理与流通平台,打通生产现场与管理系统间的数据壁垒,让数据“采得到、流得动、用得好”,加速数据价值从生产现场向经营决策层流动释放。湘潭钢铁集团的钢铁数智云,是钢铁工业智能云建设的标杆案例。

华为云官方博客 526

LakeWatch——MRS 智能运维Agent

从资源池、队列、作业等多个维度,对集群CPU与内存资源进行精细化分析与对比,直观呈现不同时间段的空闲、满载等使用状态,识别资源浪费,指导治理优化,为扩缩容决策提供数据支撑。对HDFS存储进行多维度深度分析(目录、用户、用户组等),涵盖使用量、增量、文件大小分布及数据热度等指标,帮助快速识别增长较快的目录、长期未访问的文件,统计目录文件数量与小文件占比,评估HDFS总存储量与扩缩容需求,为存储治理与资源规划提供全面数据支撑。Agent主动巡检,识别异常趋势并提前预警,让运维从"事后处理"转向"事前预防"。

华为云官方博客 515

华为云专题文档发布:丰富的AI案例、选型指导和概念解读

发布 “云服务选型”、“云计算概念”专题,提供云服务选型指导,助您选择匹配业务的云服务,解读云计算相关概念,开启云上学习之路。开发者工具和文档专区上线,提供从学习、实践到反馈的全链路支持。帮助中心新增100余篇AI案例。

华为云官方博客 286

一个人,也能用AI做点“星东西”

华为云星耀创想者大赛-2026华为云OPC创意大赛等你来~

华为云官方博客 290

从需求到可执行工作项:MCP+Skill 让智能体规划真正落地

回顾整个体验,以前让智能体帮我拆需求,它是洋洋洒洒给我列了一大篇 Markdown,看着挺像那么回事,但最后还是得我一条条往 CodeArts Req 里搬,搬完再手动挂父子关系、排日期,拆需求五分钟,搬运两小时。现在好了,MCP 给智能体接上了"手",Skill 给它装上了"项目经理的脑子",一句话下去,34 个工作项连带排期、层级关系全给我建好了,甘特图一拉,齐刷刷都在两周内,节省了多少工作量啊,美滋滋。本次实操在码道代码智能体基础上,构建了一套"需求→可执行工作项"的自动化规划方案。

华为云官方博客 575

华为云码道「码力续航计划」更新!

✅上新GLM‑5.3‑Flash,高速响应,代码生成、工程解析、Agent调试高效输出。新增GLM‑5.3‑Flash福利模型,每日解锁1000万免费Tokens。● 本次活动共发放总量价值100万元Tokens,发完即止!把耗算力的编码重活,交给华为云码道代码智能体🚀🚀。● 每日额度准时刷新,当日清零、次日满血重置。✅复杂算法、大项目解析、批量代码生成随便跑。✅不用抠额度、不用算消耗,放开调试大胆迭代。✅无需额外操作,登录即送,直接切换模型使用。● 把算力交给码道,让撸码不再内耗👏🏻。

华为云官方博客 685

【公共云三十问 之二十四】国计民生之交通:交通云如何铺就数智通衢新坦途?

交通行业作为支撑实体经济的关键基础设施,涵盖公路、铁路、机场、港口、地铁等众多子领域,其中,公路网络作为综合交通运输体系的基础骨架,承担着全国超过70%的客货运量,其数字化、智能化转型的需求尤为迫切。方面,提供Agent开发框架、知识库管理、RAG工程、意图识别、静态应用编排及模型评测等能力,支持客户将行业知识、业务流程与AI能力深度融合,快速构建面向收费稽核、路网调度、应急处置等场景的智能应用。开发并实现落地应用,全面覆盖建设、管理、养护、运营、服务、安全、办公七大业务领域。

华为云官方博客 461

【公共云三十问 之二十五】国计民生之电力:电力云如何点亮数智电力新引擎?

方案构建了覆盖数据获取、质量评估到标准化处理的全链路能力。基于公共云服务商智算底座及气象大模型,通过时空图神经网络重新建模产流机制,中国华电建成超50TB多源融合数据集,突破时空建模与机理融合等五大关键技术,短期径流预测精度较传统机理模型提升5个百分点以上,实现15天中期径流预测精度超85%,推理效率达秒级。基于气象大模型的基础架构与预训练能力,客户可直接在大模型之上开展增量训练与微调,充分利用场站所在区域的高精度历史数据(如3公里、1公里分辨率),针对不同场站和区域的地形地貌与气候特征进行模型调优。

华为云官方博客 381
上一篇: 手把手带你玩转HetuEngine:资源规划与数据源对接
下一篇: 使用 UCS(On-Premises) 管理您的GPU资源池,释放AI大模型算力潜能
华为云开发者联盟
华为云开发者联盟 企业官方账号 企业官方账号
博客等级 码龄10年 72万+粉丝 5985原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值