【深入浅出Spring6】第一期——入门

2023-05-16

一、Spring 引言

🌔 1、准备工作

(1)创建一个空项目 Spring6,为其配置JDKMaven
(2)创建一个字模块 spring6-001-revelation
(3)创建 dao、service、web 层,进而创建图片中的文件或目录【MVC
在这里插入图片描述
🌔 2、需求分析

  • 我们想完成简单的从MySQL中删除数据的功能,所以通过MVC三层架构进行模拟整个操作流程
  • web 层调用 service 层, service 层调用 dao 层,层与层之间提供接口降低耦合度【视图层、业务层、数据层】
  • dao 层的 UserDao 接口:
package com.powernode.spring6.dao;

/**
 * 持久层,负责对数据增删改查
 * @author Bonbons
 * @version 1.0
 */
public interface UserDao {
    /**
     * 根据 id 删除用户信息
     */
    void deleteById();
}
  • 对应接口的实现类:
package com.powernode.spring6.dao.impl;

import com.powernode.spring6.dao.UserDao;

/**
 * @author Bonbons
 * @version 1.0
 */
public class UserDaoImplForMySQL implements UserDao {
    @Override
    public void deleteById() {
        System.out.println("MySQL数据库正在删除用户信息......");
    }
}
  • service 层的 UserService 接口:
package com.powernode.spring6.service;

/**
 * @author Bonbons
 * @version 1.0
 */
public interface UserService {
    /**
     * 删除用户信息
     */
    void deleteUser();
}
  • 对应接口的实现类:
package com.powernode.spring6.service.impl;

import com.powernode.spring6.dao.UserDao;
import com.powernode.spring6.dao.impl.UserDaoImplForMySQL;
import com.powernode.spring6.service.UserService;

/**
 * @author Bonbons
 * @version 1.0
 */
public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImplForMySQL();
    @Override
    public void deleteUser() {
        userDao.deleteById();
    }
}
  • web 层的 UserAction 类:
package com.powernode.spring6.web;

import com.powernode.spring6.service.UserService;
import com.powernode.spring6.service.impl.UserServiceImpl;

/**
 * 表示层
 * @author Bonbons
 * @version 1.0
 */
public class UserAction {
    // 创建业务层的对象
    private UserService userService = new UserServiceImpl(); [违背DIP原则]
    // 删除用户信息的请求
    public void deleteRequest(){
        userService.deleteUser();
    }
}
  • client 层的测试类:
package com.powernode.spring6.client;

import com.powernode.spring6.web.UserAction;

/**
 * @author Bonbons
 * @version 1.0
 */
public class Test {
    public static void main(String[] args) {
        UserAction userAction = new UserAction();
        userAction.deleteRequest();
    }
}

运行测试:: 可以正常的执行业务

在这里插入图片描述
🌔 3、问题分析:

(1)这是我们面向MySQL数据库提供的操作,如果我们想扩展功能,对Oracle数据库提供操作怎么办?

我们可以重写个 UserDaoImplForOracle 接口实现类,但是后面要修改一些代码片段以满足需求。

(2)这样做,就导致了我们这个程序违背了 OCP开闭原则、DIP 依赖倒置原则。

(3)那么什么是 OCP 原则、什么是 DIP 原则呢?

$ OCP 开闭原则

📖 什么是 OCP

  • OCP 开闭原则是软件七大开发原则当中最基本的一个原则,其它六个原则都是为其服务的

📖 如何判断是否满足 OCP 原则?

在扩展系统功能时,没有修改原来已经写好的代码,就是符合OCP原则的;反之,就违背了OCP原则

  • 而且,如果我们扩展功能修改了之前稳定的程序,就要将这个项目所有程序进行测试

$ DIP 依赖倒置原则

📖 什么是 DIP

  • 面向接口编程,面向抽象编程,不要面向具体编程
  • 上面的案例在各层间相互创建实例化对象的时候,调用的就是具体的接口实现类,所以违背了依赖倒置原则

请添加图片描述
📖 如何判断是否满足依赖倒置原则?

上层不依赖具体的下层,就符合DIP原则,否则就违背了DIP原则

  • 依赖倒置原则的目的就是为了 降低程序的耦合度,提高扩展力

$ IoC 控制反转

📖 那么对于上述出现的问题我们应该如何解决呢?

我们可以采用控制反转的思想, Inversion of Control

📖 什么是控制反转?反转的是什么?

  • 控制反转是一种编程思想,也有人称之为一种新型的设计模式

  • 反转包括两部分:

    • 在程序中不再采用硬编码的方式 new 对象
    • 在程序中不再采用硬编码的方式来维护对象间的关系
  • 引出我们的 Spring 框架

📖 Spring 框架与控制反转有什么关系?

  • Spring框架实现了控制反转IoC这种思想
    • Spring框架可以帮你new对象。
    • Spring框架可以帮你维护对象和对象之间的关系。
  • Spring是一个实现了IoC思想的容器。

📖 Spring 框架是如何实现控制反转的呢?

  • 控制反转的实现方式有多种,其中比较重要的叫做:依赖注入(Dependency Injection,简称DI)。
    • 控制反转是思想。依赖注入是这种思想的具体实现。
  • 依赖注入DI,又包括常见的两种方式:
    • 第一种:set注入(执行set方法给属性赋值)
    • 第二种:构造方法注入(执行构造方法给属性赋值)
  • 依赖注入 中 “依赖”是什么意思? “注入”是什么意思?
    • 依赖:A对象和B对象的关系。
    • 注入:是一种手段,通过这种手段,可以让A对象和B对象产生关系
    • 依赖注入:对象A和对象B之间的关系,靠注入的手段来维护。【set注入和构造注入】

二、Spring 概述

📖 1、什么是 Spring ?

  • Spring 是一个轻量级控制反转(IoC)和面向切片(AOP)的容器框架
  • 让程序员只需关注核心业务的实现,可以简化开发

📖 2、Spring 的八大模块【在Spring5之后新增了WebFlux模块,之前是七大模块】
请添加图片描述
(1)Spring Core 模块

  • Spring 框架最基础的部分,提供了依赖注入来实现容器对Bean的管理。【在Spring中一切皆Bean
  • Spring 框架的核心组件是 BeanFactory,属于工厂模式的一个实例,使用IoC将应用配置和依赖从实际的应用代码分离出来

(2)Spring Context 模块

  • 该模块扩展了 BeanFactory,属于一个上下文模块,BeanFactory使Spring成为容器,该模块辅助进而使Spring成为框架
  • 增加了例如电子邮件、JNDI访问、EJB集成、远程以及时序调度(scheduling)服务等

(3)Spring AOP 模块

  • 该模块基于Spring的应用程序中的对象提供了事务管理服务,属于一种面向切片的编程
  • 使用该模块就可以不依赖组件将声明性事务管理集成到应用程序中,可以自定义拦截器、切点、日志操作等

(4)Spring DAO 模块

  • 提供了一个JDBC的抽象层和异常层次结构,用于简化JDBC

(5)Spring ORM 模块

  • 这个是Spring自己的ORM模块,可以使用
  • 也继承了其他ORM框架,包括Hibernate、JDO和iBATIS SQL映射,这些都遵从 Spring 的通用事务和 DAO 异常层次结构

(6)Spring Web MVC 模块

  • 也是Spring自己的功能全面的MVC框架,也支持使用其他集成的MVC框架

(7)Spring WebFlux 模块

Spring Framework 中包含的原始 Web 框架 Spring Web MVC 是专门为 Servlet API 和 Servlet 容器构建的。反应式堆栈 Web 框架 Spring WebFlux 是在 5.0 版的后期添加的。它是完全非阻塞的,支持反应式流(Reactive Stream)背压,并在Netty,Undertow和Servlet 3.1+容器等服务器上运行。

(8)Spring Web 模块

  • Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文,提供了Spring和其它Web框架的集成,比如Struts、WebWork
  • 提供了一些面向服务支持,例如:实现文件上传的multipart请求。

📖 3、Spring 具有哪些特点呢?

  • 轻量
    • 从大小与开销两方面而言Spring都是轻量的。
    • Spring是非侵入式的:Spring应用中的对象不依赖于Spring的特定类。【不使用其他API或容器】
  • 控制反转
    • Spring通过一种称作控制反转(IoC)的技术促进了松耦合。
    • 当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。
    • 容器在对象初始化时不等对象请求就主动将依赖传递给它
  • 面向切面
    • Spring提供了面向切面编程的丰富支持
    • 允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。
    • 应用对象只完成业务逻辑
  • 容器
    • Spring包含并管理应用对象的配置和生命周期【容器】
    • 可以配置每个bean基于一个可配置原型(prototype)如何被创建:
      • 你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例
      • 以及它们是如何相互关联的。
    • Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
  • 框架
    • Spring可以将简单的组件配置、组合成为复杂的应用。
    • Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。
    • Spring也提供了很多基础功能【事务管理、持久化框架集成等】
    • 所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

📖 4、该系列软件版本的要求:【我以我使用的版本为例】

  • IDEA 工具:2022.2.3
  • JDK: Java17【Spring6要求JDK最低版本是Java17】
  • Maven:3.8.3
  • Spring:6.0.0-M2
  • JUnit:4.13.2

三、Spring 入门程序

📖 1、Spring 压缩包解压后的几个文件都代表什么?【因为我用Maven构建项目,所以就不去下载Spring了】

  • docs:Spring框架的API帮助文档 【离线的帮助文档】
  • libs:Spring框架的jar文件 【我们实际开发使用的就是Spring提供的这些Jar包】
  • schema:Spring框架的XML配置文件相关的约束文件【类似于能用哪些标签、只能用于什么位置】

📖 2、对其中一些JRE文件的含义进行解释:

包名含义
spring-aop-5.3.9.jar这个jar 文件包含在应用中使用Spring 的AOP 特性时所需的类
spring-aspects-5.3.9.jar提供对AspectJ的支持,以便可以方便的将面向切面的功能集成进IDE中
spring-beans-5.3.9.jar这个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion ofControl / Dependency Injection(IoC/DI)操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar 及spring-beans.jar 文件就可以了。
spring-core-5.3.9.jarSpring 框架基本的核心工具类。Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统中使用这些工具类。
spring-jdbc-5.3.9.jarSpring对JDBC的支持。
spring-orm-5.3.9.jarSpring集成ORM框架的支持,比如集成hibernate,mybatis等。
spring-tx-5.3.9.jar为JDBC、Hibernate、JDO、JPA、Beans等提供的一致的声明式和编程式事务管理支持。
spring-web-5.3.9.jarSpring集成MVC框架的支持,比如集成Struts等。
spring-webflux-5.3.9.jarWebFlux是 Spring5 添加的新模块,用于 web 的开发,功能和 SpringMVC 类似的,Webflux 使用当前一种比较流程响应式编程出现的框架。
spring-webmvc-5.3.9.jarSpringMVC框架的类库

📖 3、创建我们的第一个Spring程序

(1)创建一个新的模块: spring6-002-first【普通Maven模块】
(2)修改我们的pom.xml文件,打jar包,导入我们需要的依赖

  • 此处需要注意,由于Spring6当前是里程碑版本,所以我们需要加载指定的仓库
<!--配置多个仓库repositories标签-->
<repositories>
	<repository>
		<id>repository.spring.milestone</id>
		<name>Spring Milestone Repository</name>
		<url>https://repo.spring.io/milestone</url>
	</repository>
</repositories>
  • 导入Spring6的依赖和用于单元测试的junit依赖以及log4j的日志依赖
	<!--配置相关依赖-->
    <dependencies>
        <!--spring context依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <!--log4j2的依赖-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>2.19.0</version>
        </dependency>
    </dependencies>

(3)在com.powernode.spring6.bean包下创建User

package com.powernode.spring6.bean;

/**
 * @author Bonbons
 * @version 1.0
 */
public class User {
}

com.powernode.spring6.dao包下创建UserDaoImplForMySQL

package com.powernode.spring6.dao;

/**
 * @author Bonbons
 * @version 1.0
 */
public class UserDaoImplFroMySQL {
    public void insert(){
        System.out.println("MySQL 正在保存用户信息");
    }
}

在类的根路径下编写我们的spring.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">

    <!--配置信息 id代表唯一标识,class代表全限定类名-->
    <bean id="userBean" class="com.powernode.spring6.bean.User" />
    <bean id="userDaoBean" class="com.powernode.spring6.dao.UserDaoImplFroMySQL" />
</beans>

com.powernode.spring6.test包下创建FirstSpringTest

package com.powernode.spring6.test;

import com.powernode.spring6.dao.UserDaoImplFroMySQL;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Bonbons
 * @version 1.0
 */
public class FirstSpringTest {
    @Test
    public void testFirstSpringCode(){
        // 获取Spring容器的实例[启动服务]
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        // 根据id获取我们的容器中的具体对象
        Object userBean = applicationContext.getBean("userBean");
        System.out.println(userBean);
        // 获取对象的时候直接指定类型
        UserDaoImplFroMySQL userDaoBean = applicationContext.getBean("userDaoBean", UserDaoImplFroMySQL.class);
        userDaoBean.insert();
        System.out.println(userDaoBean);
    }
}

在这里插入图片描述

📖 4、根据我们的第一个入门程序分析使用Spring的小技巧:

(1)在Spring配置文件中,通过bean标签加载一个类,id 是其唯一标识,不能重复,class的值为全限定类名

<!--配置了bean,Spring才会替我们管理这个对象-->
<bean id="userBean" class="com.powernode.spring6.bean.User" />

(2)Spring是如何根据类名创建对象的呢?

  • Spring 通过dom4j解析我们的xml配置文件,获取到全限定类名,然后通过反射机制调用无参构造方法创建对象
Class clazz = Class.forName("com.powernode.spring6.bean.User");
Object obj = clazz.newInstance();
return obj;
  • 我们不设置构造方法,默认为我们提供一个无参构造方法,但是我们提供了有参构造方法,就一定要提供无参构造方法

(3)底层是如何存储为我们创建的对象的呢?

  • 是通过一个Map集合来存储的,key 代表我们的beanidvalue 代表我们实际生成的实例

(4)对于我们的spring配置文件有什么要求吗?

  • 对于配置文件的命名和个数都没有要求【但是我们一般都放到类路径下】,通过 new ClassPathXmlApplicationContext(“路径”) 获取
  • 如果有多个配置文件,我们通过逗号分隔开
  • 如果我们的配置文件没在类路径下,我们可以通过 new FileSystemXmlApplicationContext(“路径”)来读取xml文件
  • 配置文件中配置的类可以使用JDK的类,不一定是自定义的类,按需选取

(5)我们是通过 getBean(id) 来获取我们的对象的,有什么需要注意的地方吗?

  • 我们直接通过 getBean(id) 获得的对象类型是 Object 类型的,我们不能直接调用该对象中的方法,我们可以通过在获取对象的时候直接指定类型【以UserDaoImplFroMySQL 为例】
UserDaoImplFroMySQL userDaoBean = applicationContext.getBean("userDaoBean", UserDaoImplFroMySQL.class);
        userDaoBean.insert();
        System.out.println(userDaoBean);
  • 我们如果输入了不存在的id,并不会返回空值,而是会抛出报错

(6)ApplicationContext 的超级父接口 BeanFactory

  • BeanFactorySpring容器的超级接口,ApplicationContextBeanFactory的子接口。
  • 在获取Spring容器的时候,我们编译类型定义为BeanFactory可以扩大功能范围
// 向下转型
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring.xml");
Object vipBean = beanFactory.getBean("vipBean");
System.out.println(vipBean);

📖 5、如何启用Spring6集成的Log4j2日志框架呢?

(1)在 pom.xml 文件中引入Log4j2 的依赖

<!--log4j2的依赖-->
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.19.0</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-slf4j2-impl</artifactId>
  <version>2.19.0</version>
</dependency>

(2)在类根路径下创建log4j2.xml文件 【文件名和位置是固定的】

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

<configuration>

    <loggers>
        <!--
            level指定日志级别,从低到高的优先级:
                ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
        -->
        <root level="DEBUG">
            <appender-ref ref="spring6log"/>
        </root>
    </loggers>

    <appenders>
        <!--输出日志信息到控制台-->
        <console name="spring6log" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
        </console>
    </appenders>

</configuration>

(3)之后在运行程序的时候就可以看到日志信息了

(4)如果我们想生成自定义的日志应该怎么办呢?

  • 此处的 info 什么的可以自己选择,对应上面的日志等级【ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
Logger logger = LoggerFactory.getLogger(FirstSpringTest.class);
logger.info("我是一条日志消息");
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【深入浅出Spring6】第一期——入门 的相关文章

  • 解决Use ‘docker scan‘ to run Snyk tests against images to find vulnerabilities and learn how to fix

    解决方法 在终端输入 xff1a sudo export DOCKER SCAN SUGGEST 61 false
  • 子集全排列组合数问题(带你轻松拿捏十一道OJ题)

    目录 一 子集 二 子集II 三 全排列 四 全排列II 五 字符全排列 六 字符串大小全排列 七 组合总和 八 组合总和II 九 组合总和III 十 组合总和IV 十一 递增子序列 一 子集 剑指 Offer II 079 所有子集 力扣
  • 操作系统笔记(本科必修课)

    1 操作系统概论 1 1 定义 操作系统是计算机系统中的一个系统软件 xff0c 是一些程序模块的集合 能以尽量有效 合理的方式组织和管理计算机的软 硬件资源 xff0c 合理的组织计算机的工作流程 xff0c 控制程序的执行并向用户提供各
  • linux远程登录

    ssh实验 1 两台机器 xff1a 第一台机器作为客户端 xff0c 第二台机器作为服务器 xff0c 在第一台使用rhce xff08 我用的是user1用户 xff09 用户免密登录第二台机器 2 禁止root用户远程登录和设置三个用
  • Spring的工作流程

    经过十多天的学习 xff0c 我的脑海中开始对spring框架有了基本的认识 首先我了解了spring框架的几个基本的常见的类 xff1a BeanFactory BeanDefinition BeanFactoryPostProfesso
  • 【爬虫】2.5 BeautifulSoup使用 CSS 语法查找元素

    1 使用 CSS 语法 BeautifulSoup 除了可以使用 find 与 find all 函数查找 HTML 文档树的结点元素外 xff0c 还可以采用 CSS 类似的语法来查询 xff0c 规则是 xff1a tag select
  • Spring Bean生命周期执行流程

    Spring Bean生命周期执行流程 2023 3 31 Spring 生命周期可以分为五个阶段 xff1a 创建前准备 创建实例 依赖注入 容器缓存 销毁实例 创建前准备阶段 这个阶段主要的作用是 xff1a Bean 在开始加载之前
  • github注册以及安装教程

    github注册以及安装教程 首先 xff0c 我们了解一下github gitHub 是一个面向开源及私有软件项目的托管平台 xff0c 因为只支持 git 作为唯一的版本库格式进行托管 xff0c 故名 gitHub github 于
  • Android 音频开发——Radio服务调用(四)

    nbsp nbsp nbsp nbsp nbsp nbsp nbsp 在 Android 音频开发 Radio服务 二 中介绍了 BroadcastRadioService 的启动流程 这里我们看一下 APP 如何一步步调用到 Radio
  • photoshop照片尺寸

    photoshop 一寸照片的尺寸是多少像素 常用的1寸照片大小是2 5 3 5cm的 但是 xff0c 像素多少要取决于用途是什么了 如果是冲洗的话分辨率一般用到300dpi xff0c 那就是295 412 如果是网上传看的话分辨率一般
  • ubuntu18.04安装Chrome

    简单5步安装Chrome 1 参考 xff1a https blog csdn net Diana Z article details 89474991 1 下载 sudo wget http www linuxidc com files
  • 2022牛客多校第一场A、C、D、G、I、J

    A Villages Landlines 题意 xff1a 在一条横轴上给定 n n n 个点横坐标 x s x s
  • MATLAB矩阵操作1——删除全0列和nan列

    MATLAB矩阵操作1 删除全0列和nan列 1 对全0列或行的删除2 对全为NAN列的删除3 对存在NAN列的删除 1 对全0列或行的删除 clear a 61 0 0 0 NaN 0 NaN NaN NaN 0 0 0 5 0 0 Na
  • Spring框架的知识点

    spring框架是 一个开源的容器性质的轻量级框架 主要有三大特点 xff1a 容器 IOC 控制反转 AOP 面向切面编程 DI 依赖注入 spring框架有哪些优点 xff08 三大优点 xff09 xff08 1 xff09 容器 x
  • 6.存储系统与辅存(cache的映射方式的各种问题解析)

    存储系统体系结构 6 1 存储系统6 2 程序访问的局部性原理6 3 主存地址到cache地址的映射6 4 cache的映像方式全相联映像方式直接映像方式组相联映像方式 6 1 存储系统 衡量存储器有三个指标 xff1a 容量 速度 价格
  • 127.0.0.1是什么地址

    背景情况 xff1a 将maven项目用eclipse中的tomcat启动 xff0c 登录web网页 xff0c 使用的IP为127 0 0 1 xff0c 思考为何用的这个网址 环境配置 xff1a eclipse2020 06 xff
  • SpringMVC工作流程(超级详细版)

    目录 一 xff1a springMVC常用基本组件 二 xff1a SpringMVC执行的流程 一 xff1a springMVC常用基本组件 1 DispatcherServlet 是SpringMVC框架了里面的前端控制器 作用 x
  • ViewModel的基本用法

    本来想弄个游戏开始的倒计时 xff0c 结果用普通方法没弄出来 xff0c 后来发现需要用LifeCirle可以对页面进行实时更新 于是找了相关教材 package com example myapplication import andr
  • 【新手教程】如何在Win11上制作一个模仿MacOS的桌面?

    起因是早上蹲坑的时候偶然间在小红书上刷到一篇文章 xff0c 看了下效果图感觉还不错 xff0c 所以按照文章作者的流程来了一遍 过程中也遇到了一些小问题 xff0c 正好放假了有空就写一篇文章记录一下 先放一下效果 xff1a 1 创建下
  • Android 音频开发——Hal服务版本(五)

    nbsp nbsp nbsp nbsp nbsp nbsp nbsp 上一篇内容到 BroadcastRadioService 调用 openTuner 开启广播时调用不通的 Hal 服务 这一篇来看一下 两个服务的代码 nbsp Broa

随机推荐