Gradle基础学习(六) 认识任务Task

news2024/11/24 8:46:53

理解Gradle中的任务

Gradle的构建过程基于任务(Task)的概念,而每个任务都可以包含一个或多个动作(Action)。

任务是构建中执行的一些独立的工作单元,例如编译类、创建JAR、生成Javadoc或将存档发布到仓库。

我们使用gradle taskName或gradlew taskName来执行任务,比如build:

$ ./gradlew build 

项目中所有可用任务都是来自Gradle插件和构建脚本。

比如在子项目构建脚本中创建的任务:

可用任务清单

我们通过运行tasks任务来列出项目所有可用任务。

$ ./gradlew tasks

让我们以一个非常基本的Gradle项目为例,该项目具有以下结构:

 settings.gradle.kts文件定义了根项目名称和app子项目:

rootProject.name = "HelloGradle"

include("app")

目前app子项目的构建文件暂时是一个空文件。

为了看app子项目中的任务,运行./gradlew :app:tasks 

结果中只能看到少量的辅助任务(Help Tasks),它们是Gradle核心提供的用于分析构建的任务。其他任务,如构建项目或编译代码的任务,则是由插件来添加的。

我们接下来在app构建脚本里添加application插件:

//app/build.gradle.kts

plugins {

    id("application")

}

application插件会添加一些生命周期任务。 现在再运行./gradlew app:tasks,我们看到多了一些和构建相关的任务,比如assemble 和 build任务:

任务结果

当Gradle执行一个任务时,它会在控制台中显示任务的结果标签。

这些标签描述了一个任务是否有要执行的动作,Gradle是否执行了这些动作。动作包括但不限于编译代码、压缩文件和发布存档。

(no label) or EXECUTED

任务执行了动作。

任务有动作,Gradle执行了它们。

任务没有动作,有一些依赖项,Gradle执行了一个或多个依赖项。

UP-TO-DATE

Gradle会检查任务的输入和输出,如果输入没有变化,并且输出已经存在且是最新的,那么任务就不会被执行,并标记为UP-TO-DATE。

任务有输出和输入,但都没有改变。

任务有动作,但是告诉Gradle它不会改变输出。

任务没有动作,有一些依赖项,但所有依赖都是UP-TO-DATE, SKIPPED 或 FROM-CACHE的。

任务没有动作,也没有任何依赖项。

FROM-CACHE

Gradle检测到任务的输出已经在构建缓存中时,会直接从缓存中加载,比如build cache。 

SKIPPED

任务不执行他的动作

任务被跳过可能是因为某个先决条件未满足,或者任务被明确地配置为跳过,比如使用命令行选项--exclude-task排除。

NO_SOURCE

任务不需要执行他的动作

任务有输入和输出,但没有源文件。

FROM-CACHE和UP-TO-DATE都是Gradle优化构建过程的手段,都有助于减少不必要的任务执行,提高构建速度。可能会弄不明白什么时候是UP-TO-DATE或者FROM-CACHE,在本文后面介绍缓存任务的时候,我们再做进一步说明。 

任务组group和描述description

任务组和描述用于组织和描述任务。

Groups

任务组被用来对任务进行分类,当运行./gradlew tasks时,所有任务会被列在各自的组中,这样更容易理解它们的目的和与其他任务的关系,使用group属性设置组。

Descriptions
描述提供了任务功能的简要解释。当运行./gradlew tasks时,描述会显示在每个任务的旁边,帮助开发者了解它的用途以及如何使用它,使用description属性设置描述。

我们回头去看一下前面gradle-project执行tasks的输出结果:

:run任务属于Application分组, 对其描述是 "Runs this project as a JVM application"。 

这个任务在代码中的定义会像这样:

//app/build.gradle.kts

tasks.register("run") {

    group = "Application"

    description = "Runs this project as a JVM application."

}

私有和隐藏任务

Gradle不支持将任务标记为“私有”。

当我们运行:tasks时,默认只会显示那些分配了任务组的任务,即所谓的可见任务,而那些没有分配group的任务,就是隐藏任务, 需要注意,隐藏任务依旧可以被Gradle执行,只是不显示而已。

如下所示,我们创建了一个任务helloTask,执行./gradlew :app:tasks,任务列表里并没有找到helloTask任务。

//app/build.gradle.kts

tasks.register("helloTask") {

    println("Hello")

}

给它分配一个group 

tasks.register("helloTask") {

    group = "Other"

    description = "Hello task"

    println("Hello")

}

任务就出现在了指定的Other分组下 :

执行./gradlew tasks --all 可以显示所有任务,包括隐藏的。 

比如上面的helloHiddenTask,我们没有设置group属性,也显示在了Other分组下。 

分组任务

如果我们想要自定义执行tasks时向用户显示哪些任务,可以对任务分组并设置每个组的可见性。

示例gradle-project虽然只是一个简单的Java应用,列出的可用的任务却非常多,使用构建的开发人员很少直接需要其中的许多任务。

我们可以通过配置tasks任务,限制任务显示到一个特定的分组。

我们修改一下构建脚本,创建一个自己的分组,使用displayGroup属性来指定要显示的任务组。

//app/build.gradle.kts

val myBuildGroup = "my app build"               // Create a group name

tasks.register<TaskReportTask>("tasksAll") {    // Register the tasksAll task

    group = myBuildGroup

    description = "Show additional tasks."

    setShowDetail(true)

    println("register tasksAll")

}

tasks.named<TaskReportTask>("tasks") { 

    displayGroup = myBuildGroup

}

在Gradle中,我们执行tasks任务时,会使用此类型的一个实例TaskReportTask,其中displayGroup属性用来控制要显示的任务组,默认值是null, 可以使用命令行选项 '--group'设置,设置后就只显示这个分组的任务。

任务类别 

Gradle中的任务分为两类:

1. Actionable tasks(可操作任务)

2. Lifecycle tasks(生命周期任务)

可执行任务定义了Gradle应该执行的具体操作。例如,:compileJava 任务,它编译项目的Java代码。这些操作包括创建JAR文件、压缩文件、发布归档文件等。当你应用了一个插件,如java-library,Gradle会自动添加与该插件相关的可执行任务。

生命周期任务定义了一系列的目标(targets),你可以调用这些目标来执行一系列的操作。例如,:build 就是一个常见的生命周期任务,用于构建整个项目。这类任务本身不执行具体的操作(actions)。相反,它们捆绑了可执行任务,当调用生命周期任务时,会触发与之关联的可执行任务。 基础Gradle插件(base Gradle plugin)只添加生命周期任务。这意味着如果你没有添加任何插件,Gradle仍然会提供这些基本的生命周期任务。

我们再看一下之前例子的:tasks结果

如果我们执行:build任务,会看到有好几个任务都被执行了,包括:app:compileJava任务。

可以表述为可执行任务:compileJava捆绑到了生命周期任务:build中。 

增量任务

Gradle任务的一个关键特征是它们的增量性。

Gradle可以重用之前构建的结果。因此,如果我们之前构建过项目,并且只进行了小幅更改,那么重新运行:build将不需要Gradle执行大量工作。

例如,如果我们只修改项目中的测试代码,保持生产代码不变,执行构建将仅重新编译测试代码。Gradle将生产代码的任务标记为UP-TO-DATE,表明自上次成功构建以来,它保持不变:

缓存任务

Gradle可以使用构建缓存来重用过去构建的结果。

要启用此功能,请使用--build-cache命令行参数或在gradle.properties文件中设置org.gradle.caching=true来激活构建缓存。

此优化有可能显著加速项目的构建:

当Gradle可以从缓存中获取一个任务的输出时,它会给这个任务贴上FROM-CACHE的标签。如果经常在分支之间切换,构建缓存很方便。Gradle支持本地和远程构建缓存。

我们通过实际执行其中的compileJava源码编译任务来加深对任务结果为UP-TO-DATE和FROM-CACHE的理解:

我们把之前的gradle-project例子修改一下

//app/build.gradle.kts

//添加执行入口类

application {

    mainClass = "gradle.project.App"

}

//app/src/main/java/gradle/project/App.java

package gradle.project;

public class App {

    public static void main(String[] args) {

        System.out.println("Hello World!");

   }

}

现在app子项目是一个可执行的Java 应用程序,App类是应用的执行入口。

先./gradlew clean删除各子项目build目录,确保项目是干净的状态。

执行compileJava任务编译java,  --build-cache告诉Gradle本次使用构建缓存,需要--info选项显示一些额外的构建信息:

./gradlew --build-cache compileJava --info

Settings evaluated using settings file '/Users/roy/Downloads/gradle-project/settings.gradle'.

Using local directory build cache for the root build (location = /Users/xxx/.gradle/caches/build-cache-1, removeUnusedEntriesAfter = 7 days).

Projects loaded. Root project using build file '/Users/xxx/Downloads/gradle-project/build.gradle'.

> Task :app:compileJava

Stored cache entry for task ':app:compileJava' with cache key db35214e1886f8b0ebbcc16e2fa7a618

BUILD SUCCESSFUL in 1s

1 actionable task: 1 executed

 执行成功后,app子项目里多了build目录,输出的信息里也看到了build cache目录默认的位置Gradle User Home/caches/build-cache-1/,在其中缓存了任务的输出。

再次执行

./gradlew --build-cache compileJava --info

> Task :app:compileJava UP-TO-DATE

Build cache key for task ':app:compileJava' is 3804aa4dacefba7c96c077f8de82ae3d

Skipping task ':app:compileJava' as it is up-to-date.

BUILD SUCCESSFUL in 1s

1 actionable task: 1 up-to-date

因为我们没有做任何改动,build目录里已经最新的输出了,所以compileJava任务会跳过,此时任务被标记为UP-TO-DATE。

执行./gradlew clean删除app的build目录,然后再执行

./gradlew --build-cache compileJava --info 

> Task :app:compileJava FROM-CACHE

Build cache key for task ':app:compileJava' is db35214e1886f8b0ebbcc16e2fa7a618

Task ':app:compileJava' is not up-to-date because:

  Output property 'destinationDirectory' file /Users/xx/Downloads/gradle-project/app/build/classes/java/main has been removed.

  Output property 'destinationDirectory' file /Users/xx/Downloads/gradle-project/app/build/classes/java/main/gradle has been removed.

  Output property 'destinationDirectory' file /Users/xx/Downloads/gradle-project/app/build/classes/java/main/gradle/project has been removed.

  Output property 'options.generatedSourceOutputDirectory' file /Users/xx/Downloads/gradle-project/app/build/generated/sources/annotationProcessor/java/main has been removed.

Loaded cache entry for task ':app:compileJava' with cache key db35214e1886f8b0ebbcc16e2fa7a618

BUILD SUCCESSFUL in 1s

1 actionable task: 1 from cache

任务标记为FROM-CACHE,并且从缓存中加载了上次执行的输出,日志中也有提示:

Loaded cache entry for task ':app:compileJava' with cache key db35214e1886f8b0ebbcc16e2fa7a618

 另外,app的build目录也有了,里面的输出应该就是直接从build cache中拿过来的。

 再再一次执行./gradlew --build-cache compileJava --info, 任务又是UP-TO-DATE了。

> Task :app:compileJava UP-TO-DATE

所以,对于要执行的任务,只要项目里已经存在最新输出,它就是UP-TO-DATE;否则如果任务启用构建缓存,并且在缓存里有最新输出,就是FROM-CACHE。 

可缓存任务和不可缓存任务

在Gradle中并非所有任务都可以或应该被缓存,除了少数内置任务是可缓存外,大部分任务由于各种原因(如不可预测的输出、外部依赖、任务配置等)可能不适合缓存。这些任务通常被标记为non-cacheable。

使用--build-cache选项可以让Gradle启用构建缓存功能。当这个选项被启用时,Gradle会尝试缓存可缓存任务的输出,并在后续构建中重用这些输出。

对于non-cacheable任务,Gradle会忽略构建缓存机制,并总是执行这些任务。通常是因为这些任务的输出可能依赖于不可预测或不可重复的因素,或者任务本身的配置不允许缓存。

开发者也可以显式地配置这类任务使其可缓存。

要确定一个任务是否可缓存,你可以查看任务的输出。如果任务有一个buildCacheable属性,并且它被设置为true,那么该任务就是可缓存的。如果任务没有明确的buildCacheable属性设置,或者它被设置为false,那么该任务就是non-cacheable的。

构建缓存的有效性还取决于构建环境的稳定性和一致性。如果构建环境经常变化(例如,使用了不同的构建机器或文件系统),那么构建缓存的效果可能会受到限制。因此,在使用构建缓存时,确保构建环境的一致性是非常重要的。

开发任务

在开发Gradle任务时,我们有两个选择:

1.使用现有的Gradle任务类型,比如Zip,Copy或Delete

2.创建自己的任务类型,比如MyResolveTask或者CustomTaskUsingToolchains

任务类型就是是Gradle Task类的子类。

对于Gradle任务,有三种状态需要考虑:

1.注册任务 - 在构建逻辑中使用一个任务(由您实现或由Gradle提供)。

2.配置任务 - 定义任务的输入和输出。

3.实现任务 - 创建一个自定义任务类(即自定义类型)

注册通常使用register()方法完成。

配置任务通常使用named()方法完成。

实现任务通常是通过扩展Gradle的DefaultTask类来完成的:

①: 注册Copy类型的myCopy任务。

②: 根据Copy API为注册的myCopy任务配置它所需的输入和输出。

③: 实现一个名为MyCopyTask的自定义任务类型,它扩展了DefaultTask并定义了copyFiles任务操作。

1.注册任务

我们可以通过在构建脚本和插件中注册任务来定义Gradle要执行的操作。

使用字符串作为任务名来定义任务:

//build.gradle.kts

tasks.register("myCopy") {

   doFirst {

        // Task action = Execution code

        // Run before exiting actions

    }

    doLast {

        // Task action = Execution code

        // Run after existing actions

    }

}

register()方法会将myCopy任务添加到TaskCollection中。

2.配置任务

Gradle任务必须经过配置来完成他们的操作。比如一个任务需要ZIP一个文件,我们就必须要配置文件名和文件位置。这可以参考Gradle Zip任务提供的API,学习如何正确进行配置。

在上图示例中,我们注册了一个myCopy任务

tasks.register<Copy>("myCopy")

我们可以在注册的时候就立即用代码块配置任务:

tasks.register<Copy>("myCopy") {

   from("resources")

   into("target")

   include("**/*.txt", "**/*.xml", "**/*.properties")

}

因为这个任务是Copy类型, 是Gradle支持的任务类型,所以可以使用Copy API,如from、to。

之后在需要的地方,都可以通过named()方法查找对应名字的任务来配置:

//build.gradle.kts

tasks.named<Copy>("myCopy") {

    from("resources")

    into("target")

    include("**/*.txt", "**/*.xml", "**/*.properties")

}

 注意,在named()调用时,如果指定的任务还没有注册,就会构建失败。

3.实现任务

Gradle提供了很多任务类型,包括 Delete, Javadoc, Copy, Exec, Tar和Pmd等等,如果都满足不了我们的构建逻辑需求,我们可以实现一个自定义的任务类型。

要创建一个任务类型,需要扩展DefaultTask,然后定义为一个抽象类(不用是具体实现类):

//app/build.gradle.kts
abstract class MyCopyTask extends DefaultTask {

}

Gradle 会通过解析 build.gradle 文件中的配置动态创建任务实例,这些实例是任务类的具体实现,它们包含了在配置中设置的所有参数和指定的动作。

task("taskName")与tasks.register("taskName")

在 Gradle 中,task("taskName") 和 tasks.register("taskName") 都被用来创建新的任务,但它们属于不同的 API 并具有一些细微的差别和用法上的考虑。

传统 DSL(领域特定语言)方式:

task("taskName") 是 Gradle 的传统 DSL(领域特定语言)方法,用于在 build.gradle 文件中声明一个任务。这种方式相对直观和简单,适用于简单的任务定义。

任务注册(Tasks API)方式:

tasks.register("taskName") 是 Gradle Tasks API 的一部分,用于以编程方式注册任务。它提供了更多的灵活性和控制,尤其是在需要基于其他任务或项目配置动态创建任务时。

主要区别:传统 DSL 方法在配置阶段就执行了任务的配置代码,而 Tasks API 则允许延迟配置,直到执行阶段才执行配置代码。这有助于避免在配置阶段发生不必要的副作用。

随着 Gradle 的不断进化,Tasks API 被认为是更现代和推荐的方式来创建和注册任务。

tasks.register("taskName") 实现延迟配置的原理主要基于 Gradle 的任务生命周期和任务注册机制。

在 Gradle 构建的生命周期中,任务(Task)的创建和配置是分开的。传统的 task("taskName") 语法在项目的配置阶段(configuration phase)就立即创建并配置了任务。这意味着,即使在任务从未被执行的情况下,其配置代码也会被执行。这有时可能会导致不必要的副作用,比如提前计算了某些值,或者执行了只在任务执行时才需要的逻辑。

相比之下,tasks.register("taskName") 使用了一种不同的方法。这个方法实际上并没有立即创建任务,而是注册了一个任务工厂(TaskFactory)。这个工厂会在任务首次执行时(execution phase)被调用,从而创建任务实例并执行其配置,这就是所谓的“延迟配置”(lazy configuration)。

具体来说,当你调用 tasks.register("taskName") 时,Gradle 会创建一个 TaskRegistration 对象,该对象封装了任务的配置逻辑(即你传递给 register 方法的闭包)。这个 TaskRegistration 对象会被添加到 Gradle 的任务容器中,但不会立即创建任务实例。

当 Gradle 执行阶段到来,并且需要执行名为 "taskName" 的任务时,Gradle 会从任务容器中检索相应的 TaskRegistration 对象,并调用其工厂方法来创建任务实例。此时,闭包中的配置逻辑才会被执行,从而配置新创建的任务实例。

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

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

相关文章

人工智能中的知识表示与推理技术概述

人工智能中的知识表示与推理技术概述 一、引言二、知识表示与推理技术概述1. 描述逻辑2. Horn逻辑3. 产生式系统4. 框架系统5. 语义网络 三、知识表示与推理技术的比较四、知识表示与推理技术的未来发展 一、引言 在人工智能&#xff08;AI&#xff09;的漫长演进中&#xff0…

ICode国际青少年编程竞赛- Python-1级训练场-多变量应用

ICode国际青少年编程竞赛- Python-1级训练场-多变量应用 1、 a 1 b 2 for i in range(4):Spaceship.step(a)Dev.step(b)Dev.step(-b)a a 1b b 12、 a 2 b 5 for i in range(3):Spaceship.turnLeft()Spaceship.step(a)Spaceship.turnRight()Spaceship.step(b)a a …

STM32F103学习笔记 | 报错界面及解决方案 | 1.keil5中文注释的横竖(正与斜)问题

文章目录 一、报错界面二、解决方案参考文献 一、报错界面 二、解决方案 打开设置 在打开的设置选项卡中&#xff0c;图中Font显示的是这个软件当前设置的字体&#xff0c;可以看到字体是仿宋&#xff0c;这就是问题出现的原因&#xff0c;将之改成没有的字体就行了。 可以看…

Dell EMC Storage Unity: Remove/Install Memory Module

SP A 一个内存故障 点击system view -> Enclosures->Top查看 再次查看Alert&#xff0c; 确认内存出现问题 进入Service &#xff0c; 将SP A置为service状态 移出SP A &#xff0c;进行内存更换 更换完内存后&#xff0c;将SP A插入设备&#xff0c;并进行线缆连接 进入…

使用免费的数据恢复软件通过简单的步骤恢复丢失的数据

犯错是人之常情&#xff01;您有时可能会意外地从PC或笔记本电脑中删除重要数据&#xff0c;旧的家庭或大学视频/照片&#xff0c;如果您面临数据丢失&#xff0c;则可以使用数据恢复软件轻松恢复丢失的数据。 奇客数据恢复软件可让您从笔记本电脑&#xff0c;PC和可移动存储设…

VALSE 2024特邀报告内容解析|多模态视觉融合方法:是否存在性能极限?

2024年视觉与学习青年学者研讨会&#xff08;VALSE 2024&#xff09;于5月5日到7日在重庆悦来国际会议中心举行。本公众号将全方位地对会议的热点进行报道&#xff0c;方便广大读者跟踪和了解人工智能的前沿理论和技术。欢迎广大读者对文章进行关注、阅读和转发。文章是对报告人…

五分钟了解等级保护、风险评估和安全测评三者的区别和联系?

等级保护 基本概念&#xff1a;网络安全等级保护是指对国家秘密信息、法人和其他组织和公民的专有信息以及公开信息和存储、传输、处理这些信息的信息系统分等级实行安全保护&#xff0c;对信息系统中使用的安全产品实行按等级管理&#xff0c;对信息系统中发生的信息安全事件…

Linux-03

cat 由第一行开始显示文件内容 tac 从最后一行开始显示&#xff0c;可以看出 tac 是 cat 的倒着写 nl 显示的时候&#xff0c;顺道输出行号 more 一页一页的显示文件内容 less 与 more 类似&#xff0c;但是比 more 更好的是&#xff0c;他可以往前翻页 (空格翻页 退出q命令) h…

不是,有你们这么卖东西的?涨价是肯定的,我苟住不浪也是必然的!——早读(逆天打工人爬取热门微信文章解读)

大家说我苟&#xff0c;我笑他人看不穿 引言Python 代码第一篇 洞见 晕船法则&#xff08;深度好文&#xff09;第二篇 九边 宅男之死结尾 理性的讨论能够促进理解 而不仅仅是赢得争论 我们追求的是通过讨论增进理解 而非仅仅证明自己的正确 引言 最近的言论似乎控制得更加严格…

Study--Oracle-01-单实例部署Oracle11G-R2

Oracle版本发布介绍 Oracle 19c和12c和11g功能区别_数据库_oracle_支持 一、CentOS 7 环境准备 1、软件准备 操作系统&#xff1a;CentOS 7 数据库版本: Oracle11g R2 2、操作系统环境配置 关闭selinux &#xff0c;编辑 /etc/selinux/config文件&#xff0c;设置SELINU…

Elementui的el-footer标签使用报错

Elementui的el-footer标签使用报错 其余标签的使用没有报错信息 el-footer的报错信息 原因: ​ 警告信息表示 Vue 不识别 <el-footer> 解决方式: 在组件中进行引入和暴露

Ai时代使用语音笔记整理文稿提高创作效率

其实传统的创作方式是用钢笔或者圆珠笔手写草稿。成稿后花钱誊抄数份邮寄给出版商。 计算机普及后&#xff0c;有人开始直接使用打字机或计算机创做&#xff0c;打字其实要比手写的速度快数倍&#xff0c;这样效率的提升&#xff0c;加上文创平台基本上都是按字数给收益&#…

在Windows 11环境下,生成自签名证书

在Windows 11环境下&#xff0c;使用上述命令生成自签名证书时&#xff0c;需要注意的是Windows命令行不直接支持<(command)这样的进程替换语法。因此&#xff0c;您需要稍微调整方法来实现相同的目标。下面是分步骤的操作指南&#xff1a; ### 1. 安装OpenSSL 确保您已经…

充电宝哪家质量好?质量比较好充电宝牌子排名!

在外面时&#xff0c;想要给手机充电无非就是两个办法&#xff0c;扫一个共享充电宝&#xff0c;自己买一个充电宝随时携带&#xff0c;随时随地都能开始充电&#xff0c;虽然共享充电宝非常的方便&#xff0c;但是共享充电宝的一个借租费还是挺贵的&#xff0c;算下来还不如自…

scroll-view取消滚动条

之前在写scroll-view时&#xff0c;发现移动端自己带了滚动条&#xff0c;在横向滚动的时候就比较不好看&#xff0c;于是想着去除掉页面的滚动条。当时在uni-app官网上看到使用show-scrollbar控制滚动条是否出现&#xff0c;默认为false,于是我就十分的迷惑&#xff0c;既然默…

实例116 旋转的文字

本文仅供学习交流&#xff0c;严禁用于商业用途&#xff0c;如本文涉及侵权请及时联系将于24小时内删除 目录 1.实例说明 2.技术要点 3.实现过程 4.举一反三 3.7 图像字体 字体在图形、图像处理中具有举足轻重的作用&#xff0c;特殊的字体能够增加图像的显示效果。本节将…

Win11安装Docker Desktop运行Oracle 11g 【详细版】

oracle docker版本安装教程 步骤拉取镜像运行镜像进入数据库配置连接数据库&#xff0c;修改密码Navicat连接数据库 步骤 拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g运行镜像 docker run -d -p 1521:1521 --name oracle11g registry.cn-ha…

设备驱动中device_create函数与sys/devices目录

当调用device_create时parent参数为空时&#xff0c;新添加的设备位于sys/devices//sys/devices/virtual目录 以下面代码的为例 my_newcharled.myclass class_create(THIS_MODULE,dtled); my_newcharled.mydevice device_create(my_newcharled.myclass,NULL,my_newcharled.ne…

艾体宝方案 | 加密USB金融解决方案

在现代金融行业中&#xff0c;保护敏感数据和合规性已成为至关重要的任务。为了帮助金融公司应对移动性风险和合规挑战&#xff0c;我们提供了一种高效的加密USB解决方案。 一、为什么金融公司需要加密USB解决方案 1、降低移动性风险 金融服务公司正在迅速过渡到一种模式&a…

访问学者在外访学期间,是否可以中途回国?

在全球化的今天&#xff0c;访问学者制度已成为促进国际学术交流与合作的重要桥梁。然而&#xff0c;对于许多国外访问学者来说&#xff0c;一个常见的问题是&#xff1a;在访学期间&#xff0c;我是否可以中途回国&#xff1f;这个问题涉及到多个方面&#xff0c;包括政策法规…