【JavaEE进阶】Spring 更简单的读取和存储对象

文章目录

  • 一. 存储Bean对象
    • 1. 配置扫描路径
    • 2. 添加注解存储 Bean 对象
      • 2.1 使用五大类注解存储Bean
      • 2.2 为什么要有五大类注解?
      • 2.3 有关获取Bean参数的命名规则
    • 3. 使用方法注解储存 Bean 对象
      • 3.1 方法注解储存对象的用法
      • 3.2 @Bean的重命名
      • 3.3 同⼀类型多个 @Bean 报错
  • 二. 获取 Bean 对象(对象装配)
    • 1. 属性注入
    • 2. Setter注入
    • 3. 构造方法注入(Spring官方推荐)
    • 4. @Resource:另⼀种注入关键字

一. 存储Bean对象

1. 配置扫描路径

配置扫描路径是使用注解之前的前置工作,是非常重要的,是必须的操作项.只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 Spring 中.

首先创建一个Spring项目.创建好后,第一步就是配置扫描路径:在resources目录中创建一个spring-config.xml文件.然后在spring-config.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"xmlns:content="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><content:component-scan base-package=""></content:component-scan>
</beans>

<content:component-scan base-package=""></content:component-scan>base-package=""的值设置为需要扫描对象的根路径.注意:这个根路径是从java目录开始的.
在这里插入图片描述

2. 添加注解存储 Bean 对象

想要将对象存储在spring中,有两种注解类型可以实现:

  1. 使用类注解(五大类注解):

    • @Controller:控制器:验证用户请求的数据正确性(相当于安保系统).
    • @Service:服务:编排和调度具体执行方法(相当于客服中心).
    • @Repository:持久层:和数据库交互;(相当于执行者) = DAO(Date Access Obiect)数据访问层
    • @Component:组件;(工具类)
    • @Configuration:配置项(项目中的一些配置)
  2. 方法注解

    • @Bean

2.1 使用五大类注解存储Bean

首先,我们来了解如何使用五大类注解来储存对象

  1. @Controller

    package com.spring.demo;import org.springframework.stereotype.Controller;@Controller
    public class UserController {public void sayHi() {System.out.println("UserController sayHi!");}
    }
    

    在扫描路径下创建该UserController类.并在类上加@Controller注解,此时就将Bean存储到容器中了.

    接下来就是从 Spring 中读取出我们的对象,这里还是先使用依赖查找的方式来获取 Bean,使用五大类注解,默认情况下,Bean 的名字就是原类名首字母小写(小驼峰).

    import com.spring.demo.UserController;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {//1.获取 srping 容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//2.获取 bean 对象//获取对象时使用类名的小驼峰形式作为 name 参数UserController userController =  context.getBean("userController", UserController.class);//3.使用 beanuserController.sayHi();}
    }
    

    运行结果:
    在这里插入图片描述
    注意:要将Bean存储到Spring中需要满足两个条件:

    1. 使用五大类注解创建的类
    2. 必须在配置的扫描路径下.(包括子包)

    扫描路径也叫做根路径.两个条件缺一不可.

    为什么要设置根路径?
    设置根路径其实也是为了提高程序的性能,因为如果不设置根路径,Spring 就会扫描项目文件中所有的目录,但并不是所有类都需要储存到 Spring当中,这样性能就会比较低,设置了根路径,Spring 就只扫描该根路径下所有的目录就可以了,提高了程序的性能。下来我们演示一下没有配置扫描路径下的情况:
    在这里插入图片描述
    还需要知道的是使用注解存储的 Bean 和使用XML存储的的 Bean 是可以一同使用的,比如我们将刚刚有问题的Student重新通过XML的方式进行存储.
    在这里插入图片描述

    注意:默认情况下,使用原类名首字母小写就能读取到Bean对象.特例情况:原类名如果首字母和第二个字母都是大写的情况下,那么bean名称就是原类名.
    在这里插入图片描述

  2. @Service
    启动类中代码:

    //1.获取 srping 容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//2.获取 bean 对象//获取对象时使用类名的小驼峰形式作为 name 参数UserService userService =  context.getBean("userService", UserService.class);//3.使用 beanuserService.sayHi();
    

    UserService类:

    package com.spring.demo;import org.springframework.stereotype.Service;@Service
    public class UserService {public void sayHi(){System.out.println("UserService sayHi!");}
    }
    

    运行结果:
    在这里插入图片描述

其余三种使用方式相同,此处不再做介绍.

2.2 为什么要有五大类注解?

既然都五大类完成的是同样的工作,那为什么要有五大类注解呢?

其实五大类注解主要是为了规范 Java 项目的代码,Java 项目的标准分层如下:

  1. 控制层(Controller)
  2. 服务层(Service)
  3. 数据持久层(Dao)

而五大类注解便是对应着不同的层级别使用的,让程序猿看到某一个注解就可以明确这个了类是做什么的。
程序的⼯程分层,调⽤流程如下:
在这里插入图片描述
包括企业中也是按照这样的结构来将项目分层的,典型的比如阿里,它只是在标准分层在服务层(Service)做了一个扩展,划分的更加细致详细了.
在这里插入图片描述
五大类注解主要起到的是“见名知意”的作用,代码层面上来看,作用是类似的.查看五大类源码可知:
五大类的源码中除了 @Component 以外,其他四大类注解中都包含了 @Component 注解的功能,这四大类注解都是基于 @Component 实现的,是 @Component 拓展。

2.3 有关获取Bean参数的命名规则

上文中在使用依赖查找的方式获取Bean时,我们讲到了getBean方法的BeanName是使用类名的小驼峰形式(即类名的首字母小写)以及第一个字母和第二个字母都大写情况下的特例.

注意:BeanName的规范命名规则并不是 Spring 独创的,而依照 Java 标准库的规则进行的。

BeanName的规范命名规则:

  1. 如果类名不存在或类名为空字符串,BeanName为原类名。
  2. 如果类名字长度大于1,且第一个与第二个字符为大写,BeanName为原类名。
  3. 其他情况,BeanName为原类名的小驼峰形式.

3. 使用方法注解储存 Bean 对象

3.1 方法注解储存对象的用法

类注解是添加到某个类上的,而方法注解是放到某个方法上的.在Spring框架的设计中,方法注解@Bean要配合类注解才能将对象正常存储到Spring容器中.

举个🌰:我们有一个普通书本类

package com.spring.demo;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;@Controller
public class BookInfo {private String bookName;private String author;private String style;public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getStyle() {return style;}public void setStyle(String style) {this.style = style;}@Override@Beanpublic String toString() {return "com.spring.demo.BookInfo{" +"bookName='" + bookName + '\'' +", author='" + author + '\'' +", style='" + style + '\'' +'}';}}

下面演示使用@Bean方法注解储存对象:

package com.spring.demo;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;@Controller
public class Books {@Beanpublic BookInfo getBook(){BookInfo bookInfo = new BookInfo();bookInfo.setBookName("三体");bookInfo.setAuthor("刘慈欣");bookInfo.setStyle("文学科幻");return bookInfo;}public void sayHi(){System.out.println("Books sayHi!");}
}

启动类:

获取方法注解储存的对象时,传入的BeanName参数值默认值就是方法名,上面的代码中方法名为getBook,所以获取时,就使用getBook作为参数来进行获取。

import com.spring.demo.BookInfo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");BookInfo book =  context.getBean("getBook", BookInfo.class);System.out.println(book);}
}

运行结果:
在这里插入图片描述

3.2 @Bean的重命名

获取方法注解储存的对象时,传入的BeanName参数值默值为方法名,但像上面那样返回对象的方法名称往往是getXXX这样式取名的,虽然在语法与实现上是没有问题的,但实际开发写出这样的代码,看起来还是比较别扭的。
实际上注解 @Bean 是可以加参数的,给储存的对象起别名,像下面这个样子。

package com.spring.demo;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;@Controller
public class Books {@Bean(name = "book")public BookInfo getBook(){BookInfo bookInfo = new BookInfo();bookInfo.setBookName("三体");bookInfo.setAuthor("刘慈欣");bookInfo.setStyle("文学科幻");return bookInfo;}public void sayHi(){System.out.println("Books sayHi!");}
}

在这里插入图片描述

也可以给 Bean 设置多个别名,总结起来有如下几种方式:

//方式一(省略参数名的情况下默认是name)
@Bean("article1")
//方式二
@Bean(name = "article2")
//方式三
@Bean(value = "article3")
//起多个别名
@Bean(name = {"article4", "article5"})
@Bean(value = {"article6", "article7"})
@Bean({"article8", "article9", "article10"})

但是需要注意,当重新命名之后,就不能使用原来的方法名来获取对象了.
在这里插入图片描述
所以使用 @Bean 存储对象的beanName命名规则是,当没有设置name/value属性时,此时 Bean 的默认名字就是方法名,一旦添加了别名name/value属性后,就只能通过重命名的别名来获取 Bean 了,默认的使用方法名获取 Bean 对象就不能使用了。

@Bean 使用时,同一类如果多个 Bean 使用相同的名称,此时程序执行是不会报错的,他会根据类加载顺序和类中代码从上至下的的顺序,将第一个 Bean 存放到 Spring 中,但第一个之后的对象就不会被存放到容器中了,也就是只有在第一次创建 Bean 的时候会将对象和 Bean 名称关联起来,后续再有相同名称的Bean存储时候,容器会自动忽略。

还可以通过类注解 @Order 注解控制类加载顺序(值越小,优先级越高),进而影响 Bean 的存放的先后顺序.

3.3 同⼀类型多个 @Bean 报错

当出现以下多个 Bean,返回同⼀对象类型时程序会报错,如下代码所示:
在这里插入图片描述
在这里插入图片描述
运行结果如下:
在这里插入图片描述
报错的原因是,⾮唯⼀的 Bean 对象.
同⼀类型多个 Bean 报错处理:
解决同⼀个类型,多个 bean 的解决⽅案有以下两个:

  1. 使⽤ @Resource(name="user1") 定义。(@Resource下文有介绍)
    在这里插入图片描述
  2. 使⽤ @Qualifier 注解定义名称。
    在这里插入图片描述

二. 获取 Bean 对象(对象装配)

获取bean对象也叫做对象装配.是把bean对象取出来放到某个类中.有时候也叫对象注⼊(DI).
对象装配(对象注⼊)的实现⽅法以下 3 种:

  1. 属性注⼊
  2. 构造⽅法注⼊
  3. Setter 注⼊
    接下来,我们分别来看。
    下⾯我们按照实际开发中的模式,将 Service 类注⼊到 Controller 类中。

1. 属性注入

属性注⼊是使⽤ @Autowired 实现的,将 Service 类注⼊到 Controller 类中。
User代码:

package com.spring.demo;public class User {private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}
}

Service代码:

package com.spring.demo;import org.springframework.stereotype.Service;@Service
public class UserService {public void sayHi(){System.out.println("UserService sayHi!");}public User getUser(Integer id){User user = new User();user.setId(id);user.setName("xxxflower-"+id);return user;}}

Controller代码:

package com.spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {@Autowiredprivate UserService userService;public User getUser(Integer id){return userService.getUser(id);}public void sayHi() {System.out.println("UserController sayHi!");}
}

运行结果:
在这里插入图片描述
在这里插入图片描述
优点:简单.
缺点:

  1. 没办法实现final修饰的变量注入.
    在这里插入图片描述
  2. 兼容不好:只适用于Ioc容器.
  3. 风险:因为写法简单,所以违背单一设计原则的概率更大.

2. Setter注入

Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解,如下代码所示:

package com.spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController2 {private UserService userService;//2.使用Setter注入@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public User getUser(Integer id){return userService.getUser(id);}
}

运行结果:
在这里插入图片描述
优点:符合单一设计原则(每个方法只传递一个对象)
缺点:

  1. 不能注入不可变对象
    在这里插入图片描述
  2. 使用setter注入的对象可能会被修改.

3. 构造方法注入(Spring官方推荐)

构造⽅法注⼊是在类的构造⽅法中实现注⼊,如下代码所示:

package com.spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController3 {private UserService userService;//3.构造方法注入@Autowiredpublic UserController3(UserService userService){this.userService = userService;}public User getUser(Integer id){return userService.getUser(id);}
}

运行结果:
在这里插入图片描述
特点:如果当前类中只有一个构造方法的话,那么@Autowired 注解可以省略.
在这里插入图片描述
优点:

  1. 可以注入一个不可变对象(使用fianl修饰的对象)
    在这里插入图片描述

问题:为什么构造方法可以注入一个不可变对象,而属性注入和Setter注入却不行?
答:这是Java的规定,在java中,被final对象必须满足以下两个条件中的任意一个:

  1. final修饰的对象,是直接复制的.
  2. final修饰的对象,必须在构造方法中赋值.
  1. 注入的对象不会被改变(构造方法只能执行一次)
  2. 构造方法注入可以保证注入对象完全被初始化
  3. 通用性更好.

4. @Resource:另⼀种注入关键字

在进行类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊,如下代码所示:

package com.spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;import javax.annotation.Resource;@Controller
public class UserController {//    @Autowired@Resourceprivate UserService userService;public User getUser(Integer id){return userService.getUser(id);}public void sayHi() {System.out.println("UserController sayHi!");}
}

上述三种注入方式使用@Autowired行,使用@Resource也行,但是这两者也是有区别的:

  1. 出身不同:@Autowired 来自于 Spring,而 @Resource 来⾃于 JDK 的注解;
  2. 使⽤时设置的参数不同:相比于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如
    name 设置,根据名称获取 Bean。
  3. @Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注⼊和属性注⼊,不能⽤于构造函数注⼊。
  4. @Autowired 先根据类型查找(byType),之后再根据名称查找(byName)。@Resource 先根据名称去查,之后再根据类型去查。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/34831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot单元测试与Mybatis单表增删改查

目录 1. Spring Boot单元测试 1.1 什么是单元测试? 1.2 单元测试有哪些好处? 1.3 Spring Boot 单元测试使用 单元测试的实现步骤 1. 生成单元测试类 2. 添加单元测试代码 简单的断言说明 2. Mybatis 单表增删改查 2.1 单表查询 2.2 参数占位符 ${} 和 #{} ${} 和 …

学点Selenium玩点新鲜~,让分布式测试有更多玩法

前 言 我们都知道 Selenium 是一款在 Web 应用测试领域使用的自动化测试工具&#xff0c;而 Selenium Grid 是 Selenium 中的一大组件&#xff0c;通过它能够实现分布式测试&#xff0c;能够帮助团队简单快速在不同的环境中测试他们的 Web 应用。 分布式执行测试其实并不是一…

opencv,opengl,osg,vulkan,webgL,opencL,cuda

OpenCV OpenCV是一个基于BSD许可&#xff08;开源&#xff09;发行的跨平台计算机视觉和机器学习软件库&#xff0c;可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C 类构成&#xff0c;同时提供了Python、Ruby、MATLAB等…

安卓java A应用切换到B应用,来回切换不执行OnCreate

需求&#xff1a;安卓java如何做到A应用切换到B应用&#xff0c;如果B应用没启动就启动&#xff0c;如果B应用已经启动就仅仅切换到B应用。B应用再切换回A应用&#xff0c;不要重复执行OnCreate! 在 A 应用中的&#xff1a; 在 A 应用中&#xff0c;如果你希望在切换回 B 应用…

小米平板6Max14即将发布:自研G1 电池管理芯片,支持33W反向快充

明天晚上7点&#xff08;8 月 14 日&#xff09;&#xff0c;雷军将进行年度演讲&#xff0c;重点探讨“成长”主题。与此同时&#xff0c;小米将推出一系列全新产品&#xff0c;其中包括备受瞩目的小米MIX Fold 3折叠屏手机和小米平板6 Max 14。近期&#xff0c;小米官方一直在…

分布式搜索ElasticSearch-ES(一)

一、ElasticSearch介绍 ES是一款非常强大的开源搜索引擎&#xff0c;可以帮我们从海量的数据中快速找到我们需要的内容。 ElasticSearch结合kibana、Logstash、Beats&#xff0c;也就是elastic stack(ELK)&#xff0c;被广泛运用在日志数据分析&#xff0c;实时监控等领域。 …

accumulate函数的简单应用

accumulate函数是C numeric库中的一个函数&#xff0c;主要用来对指定范围内元素求和&#xff0c;但也自行指定一些其他操作&#xff0c;如范围内所有元素相乘、相除等。 使用前需要引用头文件&#xff1a; #include <numeric>函数共有四个参数&#xff0c;其中前三个为…

Ajax 笔记(二)—— Ajax 案例

笔记目录 2. Ajax 综合案例2.1 案例一-图书管理2.1.1 渲染列表2.1.2 新增图书2.1.3 删除图书2.1.4 编辑图书 2.2 案例二-背景图的上传和更换2.2.1 上传2.2.2 更换 2.3 案例三-个人信息设置2.3.1 信息渲染2.3.2 头像修改2.2.3 信息修改2.3.4 提示框 Ajax 笔记&#xff1a; Ajax…

React Native 列表组件基础知识

ScrollView 组件 ScrollView组件是一个容器滚动组件&#xff0c;当容器超出指定宽高时就可以进行滚动交互。 ScrollView组件是一次性渲染所有的 React 子组件&#xff0c;这在性能上是比较差的&#xff0c;所以不建议当列表特别长的时候使用此组件。 接下来列举几个常用的一…

HTML(JavaEE初级系列12)

目录 前言&#xff1a; 1.HTML结构 1.1认识HTML标签 1.2HTML文件基本结构 1.3标签层次结构 1.4快速生成代码框架 2.HTML常见标签 2.1注释标签 2.2标题标签&#xff1a;h1-h6 2.3段落标签&#xff1a;p 2.4换行标签&#xff1a; br 2.5格式化标签 2.6图片标签&#…

【数据结构•堆】经典问题:k路归并

题目描述 k路归并问题&#xff1a;   把k个有序表合并成一个有序表。&#xff08; k < 10^4 &#xff09; 输入输出格式 输入格式&#xff1a; 输入数据共有 2*k1 行。   第一行&#xff0c;一个整数k&#xff08; k < 10^4 &#xff09;&#xff0c;表示有k个有序…

【详细教程】学会使用Python隧道代理

作为一名专业爬虫程序猿&#xff0c;我深知在进行网络数据采集时&#xff0c;可能会面临网络封锁、隐私泄露等问题。今天&#xff0c;我将与大家分享如何学会使用Python隧道代理&#xff0c;帮助我们自由访问受限网站&#xff0c;同时保护了解探索Python隧道代理&#xff01; …

3.1 Spring MVC概述

1. MVC概念 MVC是一种编程思想&#xff0c;它将应用分为模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;、控制器&#xff08;Controller&#xff09;三个层次&#xff0c;这三部分以最低的耦合进行协同工作&#xff0c;从而提高应用的可扩展性及可维护…

C++ opencv:视频读取、变换颜色风格、保存

1. 相关知识点 VideoCapture&#xff1b; applyColorMap&#xff1b; VideoWriter&#xff1b; 2. 代码 编写代码main.cpp: #include<iostream> #include "opencv2/opencv.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/highgu…

解开谜团:为什么红黑树胜过AVL树?

为什么红黑树胜过AVL树 博主简介一、引言1.1、红黑树和AVL树简介1.2、红黑树在某些方面优于AVL树 二、红黑树和AVL树的基本原理2.1、红黑树的定义和性质2.2、AVL树的定义和性质2.3、对比两种树结构的特点 三、插入和删除操作的复杂性比较3.1、红黑树的插入操作和平衡性维护3.2、…

幂次方(c++题解)

题目描述 任何一个正整数都可以用 22 的幂次方表示。例如 1372^72^32^0。 同时约定方次用括号来表示&#xff0c;即 a^b 可表示为 a(b)。 由此可知&#xff0c;137137 可表示为 2(7)2(3)2(0) 进一步&#xff1a; 7 2^222^0 ( 2^121 用 2 表示)&#xff0c;并且 322^0。 所…

Spring Boot 重启命令

Spring Boot 重启命令 本文描述了一个重启Spring Boot命令执行过程和示例 本文利用kill -9 关闭进程&#xff0c;不优雅&#xff0c;会突然中断程序&#xff0c;可能导致数据和逻辑异常 搜索微信小程序【亚特技术】在资源中搜索【优雅】可得到Spring Boot如何优化重启 1. 过…

【Bert101】变压器模型背后的复杂数学【02/4】

一、说明 众所周知&#xff0c;变压器架构是自然语言处理&#xff08;NLP&#xff09;领域的突破。它克服了 seq-to-seq 模型&#xff08;如 RNN 等&#xff09;无法捕获文本中的长期依赖性的局限性。变压器架构被证明是革命性架构&#xff08;如 BERT、GPT 和 T5 及其变体&…

【阵列信号处理】空间匹配滤波器、锥形/非锥形最佳波束成形器、样本矩阵反演 (SMI) 研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

九耶丨阁瑞钛伦特-产品经理面试题

在产品上线后&#xff0c;会着重观察6类指标&#xff1a; 1、活跃用户指标 衡量APP用户规模的指标&#xff0c;一个产品是否成功&#xff0c;如果只看一个指标&#xff0c;那么这个指标一定是活跃用户数。 日活(DAU)&#xff1a;一天内日均活跃设备数(去重&#xff0c;每个公…