2021年 最新 多阶段构建dockerfile实现java源码编译打jar包并做成镜像

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 多阶段构建指在Dockerfile中使用多个FROM语句,每个FROM指令都可以使用不同的基础镜像,并且是一个独立的子构建阶段。使用多阶段构建打包Java应用具有构建安全、构建速度快、镜像文件体积小等优点.

背景信息

镜像构建的通用问题

镜像构建服务使用Dockerfile来帮助用户构建最终镜像,但在具体实践中,存在一些问题:

Dockerfile编写有门槛

开发者(尤其是Java)习惯了语言框架的编译便利性,不知道如何使用Dockerfile构建应用镜像。


镜像容易臃肿

构建镜像时,开发者会将项目的编译、测试、打包构建流程编写在一个Dockerfile中。每条Dockerfile指令都会为镜像添加一个新的图层,从而导致镜像层次深,镜像文件体积特别大。


存在源码泄露风险

打包镜像时,源代码容易被打包到镜像中,从而产生源代码泄漏的风险。


多阶段构建优势

针对Java这类的编译型语言,使用Dockerfile多阶段构建,具有以下优势:

保证构建镜像的安全性

当您使用Dockerfile多阶段构建镜像时,需要在第一阶段选择合适的编译时基础镜像,进行代码拷贝、项目依赖下载、编译、测试、打包流程。在第二阶段选择合适的运行时基础镜像,拷贝基础阶段生成的运行时依赖文件。最终构建的镜像将不包含任何源代码信息。


优化镜像的层数和体积

构建的镜像仅包含基础镜像和编译制品,镜像层数少,镜像文件体积小。


提升构建速度

使用构建工具(Docker、Buildkit等),可以并发执行多个构建流程,缩短构建耗时。


使用多阶段构建Dockerfile

以Java Maven项目为例,在Java Maven项目中新建Dockerfile文件,并在Dockerfile文件添加以下内容。

说明 该Dockerfile文件使用了二阶段构建。


第一阶段:

选择Maven基础镜像(Gradle类型也可以选择相应Gradle基础镜像)完成项目编译,拷贝源代码到基础镜像并运行RUN命令,从而构建Jar包。


第二阶段:

拷贝第一阶段生成的Jar包到OpenJDK镜像中,设置CMD运行命令。


方案一:


通俗易懂篇:


# First stage: complete build environment
FROM maven:3.5.0-jdk-8-alpine AS builder
# add pom.xml and source code
ADD ./pom.xml pom.xml
ADD ./src src/
# package jar
RUN mvn clean package
# Second stage: minimal runtime environment
From openjdk:8-jre-alpine
# copy jar from the first stage
COPY --from=builder target/my-app-1.0-SNAPSHOT.jar my-app-1.0-SNAPSHOT.jar
EXPOSE 8080
CMD ["java", "-jar", "my-app-1.0-SNAPSHOT.jar"]


方案二:


对于一个 Java 应用,如果要部署到 Kubernetes,首先需要创建一个容器镜像。这其实由两个步骤组成:


构建 Java 源代码,并打包成 JAR 文件。


把 JAR 文件和 JDK 组合在一起,创建出容器镜像。


在一般的构建过程中,这两个步骤是分开的。第一步由本地机器上的 Maven 或 Gradle 来完成,第二步使用 Docker 命令从 Dockerfile 中创建出镜像,并使用第一步构建出的本地 JAR 文件。


当需要使用某些公开容器镜像注册表(如 Docker Hub 和 Quay.io)提供的持续集成功能时,就不能再分成两个步骤,因为这些注册表只支持构建容器镜像,并没有提供应用构建的支持。


通过使用 Docker 提供的多阶段构建(multi-stage build)功能,我们可以很容易地把这两个步骤合成一个。


对于一个 Spring Boot 应用,下面的 Dockerfile 文件可以完成从源代码到镜像的构建。第一个阶段使用 Maven 镜像作为基础,在把 src 目录和 pom.xml 复制到镜像中之后, 使用 Maven 命令来编译源代码并打包。builder 是这个阶段的名称。在这个阶段完成之后,/build/target 目录中包含了所产生的 JAR 文件。


第二个阶段使用 OpenJDK 11 Alpine 镜像作为基础, COPY 命令把第一个阶段产生的 JAR 文件复制到当前镜像中。–from=builder 参数指定了复制的来源是第一个阶段产生的镜像。



大牛篇;


FROM maven:3.6.3-openjdk-8 AS builder
 #  AS builder 起别名
RUN mkdir /build
# 创建临时文件
ADD src /build/src
#将 src目录复制到临时目录
ADD pom.xml /build
# 将 pom文件复制到临时目录
RUN cd /build && mvn -B -ntp package
# 打包
FROM adoptopenjdk/openjdk8:alpine-jre
# 获取jre
COPY --from=builder /build/target/ems-0.0.1-SNAPSHOT.jar /ems.jar
#从标记点 拷贝jar包 并改名
CMD ["java", "-jar", "/ems.jar"]
# 声明运行方式


当使用 Docker 命令来构建这个 Dockerfile 文件之后,所得到的镜像中只包含 JAR 文件和 JDK。


IDEA文件结构如下:


image.png


命令行信息对比:

[root@localhost ~/myems]# docker build -t ems1:1.0 .
Sending build context to Docker daemon  32.77kB
Step 1/8 : FROM maven:3.6.3-openjdk-8 AS builder
 ---> d1b3f61d61f2
Step 2/8 : RUN mkdir /build
 ---> Running in 08cadf2db7b4
Removing intermediate container 08cadf2db7b4
 ---> 836eeb13f7fe
Step 3/8 : ADD src /build/src
 ---> b5d73ef7ed79
Step 4/8 : ADD pom.xml /build
 ---> 5e9a5ce77859
Step 5/8 : RUN cd /build && mvn -B -ntp package
 ---> Running in d92bbcd7ab54
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------------------< com.baizhi:ems >---------------------------
[INFO] Building ems 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ ems ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ ems ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 6 source files to /build/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ ems ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] skip non existing resourceDirectory /build/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ ems ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /build/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ ems ---
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.baizhi.EmsApplicationTests
12:11:00.101 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate]
12:11:00.200 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)]
12:11:02.814 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.baizhi.EmsApplicationTests] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper]
12:11:03.386 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.baizhi.EmsApplicationTests], using SpringBootContextLoader
12:11:03.427 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.baizhi.EmsApplicationTests]: class path resource [com/baizhi/EmsApplicationTests-context.xml] does not exist
12:11:03.428 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.baizhi.EmsApplicationTests]: class path resource [com/baizhi/EmsApplicationTestsContext.groovy] does not exist
12:11:03.428 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [com.baizhi.EmsApplicationTests]: no resource found for suffixes {-context.xml, Context.groovy}.
12:11:03.456 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [com.baizhi.EmsApplicationTests]: EmsApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
12:11:03.870 [main] DEBUG org.springframework.test.context.support.ActiveProfilesUtils - Could not find an 'annotation declaring class' for annotation type [org.springframework.test.context.ActiveProfiles] and class [com.baizhi.EmsApplicationTests]
12:11:07.746 [main] DEBUG org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider - Identified candidate component class: file [/build/target/classes/com/baizhi/EmsApplication.class]
12:11:07.812 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration com.baizhi.EmsApplication for test class com.baizhi.EmsApplicationTests
12:11:11.875 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [com.baizhi.EmsApplicationTests]: using defaults.
12:11:11.876 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.event.ApplicationEventsTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener]
12:11:12.008 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@29215f06, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@59505b48, org.springframework.test.context.event.ApplicationEventsTestExecutionListener@4efac082, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@6bd61f98, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@48aca48b, org.springframework.test.context.support.DirtiesContextTestExecutionListener@13fd2ccd, org.springframework.test.context.transaction.TransactionalTestExecutionListener@b9b00e0, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@506ae4d4, org.springframework.test.context.event.EventPublishingTestExecutionListener@7d4f9aae, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@72e5a8e, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@54e1c68b, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@53aac487, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@52b1beb6, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@273e7444, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener@7db12bb6]
12:11:12.022 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test class: context [DefaultTestContext@5d534f5d testClass = EmsApplicationTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@2e3967ea testClass = EmsApplicationTests, locations = '{}', classes = '{class com.baizhi.EmsApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@670002, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@56528192, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@460d0a57, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@6af93788, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4a22f9e2, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@21bcffb5], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true]], class annotated with @DirtiesContext [false] with mode [null].
12:11:12.467 [main] DEBUG org.springframework.test.context.support.TestPropertySourceUtils - Adding inlined properties to environment: {spring.jmx.enabled=false, org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.2)
2021-06-29 12:12:10.365  INFO 69 --- [           main] com.baizhi.EmsApplicationTests           : Starting EmsApplicationTests using Java 1.8.0_282 on d92bbcd7ab54 with PID 69 (started by root in /build)
2021-06-29 12:12:10.368  INFO 69 --- [           main] com.baizhi.EmsApplicationTests           : No active profile set, falling back to default profiles: default
2021-06-29 12:18:11.149  INFO 69 --- [           main] com.baizhi.EmsApplicationTests           : Started EmsApplicationTests in 418.516 seconds (JVM running for 494.655)
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 514.628 s - in com.baizhi.EmsApplicationTests
2021-06-29 12:19:24.357  INFO 69 --- [ionShutdownHook] com.alibaba.druid.pool.DruidDataSource   : {dataSource-0} closing ...
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] 
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ ems ---
[INFO] Building jar: /build/target/ems-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.5.2:repackage (repackage) @ ems ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  19:22 min
[INFO] Finished at: 2021-06-29T12:20:33Z
[INFO] ------------------------------------------------------------------------
Removing intermediate container d92bbcd7ab54
 ---> e19081a12cd6
Step 6/8 : FROM adoptopenjdk/openjdk8:alpine-jre
alpine-jre: Pulling from adoptopenjdk/openjdk8
540db60ca938: Pull complete 
9fc18144b37f: Pull complete 
cc610e703026: Pull complete 
Digest: sha256:4e7f3fc23cfd6e9751a1465fc4daa2073a3987c72b178ba467b41f3971751205
Status: Downloaded newer image for adoptopenjdk/openjdk8:alpine-jre
 ---> 32011de768b3
Step 7/8 : COPY --from=builder /build/target/ems-0.0.1-SNAPSHOT.jar /ems.jar
 --->32011de768b3
Step 8/8 : CMD ["java", "-jar", "/ems.jar"]
 ---> Running in cc75371d3a8f
Removing intermediate container cc75371d3a8f
 ---> 32011de768b3
Successfully built 32011de768b3
Successfully tagged ems:1.0


最终效果:

[root@localhost ~/myems]# docker build -t ems:2.0 .  
Sending build context to Docker daemon  32.77kB
Step 1/8 : FROM maven:3.6.3-openjdk-8 AS builder
 ---> d1b3f61d61f2
Step 2/8 : RUN mkdir /build
 ---> Using cache
 ---> 836eeb13f7fe
Step 3/8 : ADD src /build/src
 ---> Using cache
 ---> b5d73ef7ed79
Step 4/8 : ADD pom.xml /build
 ---> Using cache
 ---> 5e9a5ce77859
Step 5/8 : RUN cd /build && mvn -B -ntp package
 ---> Using cache
 ---> e19081a12cd6
Step 6/8 : FROM adoptopenjdk/openjdk8:alpine-jre
 ---> 32011de768b3
Step 7/8 : COPY --from=builder /build/target/ems-0.0.1-SNAPSHOT.jar /ems.jar
 ---> 84666655f883
Step 8/8 : CMD ["java", "-jar", "/ems.jar"]
 ---> Running in cc75371d3a8f
Removing intermediate container cc75371d3a8f
 ---> 554142c1b512
Successfully built 554142c1b512
Successfully tagged ems:2.0


最终镜像制作成功

59.png


目录结构~

60.png


如果大家觉得还不错,点赞,收藏,分享,一键三连支持我一下~

相关实践学习
通过ACR快速部署网站应用
本次实验任务是在云上基于ECS部署Docker环境,制作网站镜像并上传至ACR镜像仓库,通过容器镜像运行网站应用,网站运行在Docker容器中、网站业务数据存储在Mariadb数据库中、网站文件数据存储在服务器ECS云盘中,通过公网地址进行访问。
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
30天前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
216 8
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
Java与生成式AI:构建内容生成与创意辅助系统
生成式AI正在重塑内容创作、软件开发和创意设计的方式。本文深入探讨如何在Java生态中构建支持文本、图像、代码等多种生成任务的创意辅助系统。我们将完整展示集成大型生成模型(如GPT、Stable Diffusion)、处理生成任务队列、优化生成结果以及构建企业级生成式AI应用的全流程,为Java开发者提供构建下一代创意辅助系统的完整技术方案。
163 10
|
1月前
|
人工智能 算法 Java
Java与AI驱动区块链:构建智能合约与去中心化AI应用
区块链技术和人工智能的融合正在开创去中心化智能应用的新纪元。本文深入探讨如何使用Java构建AI驱动的区块链应用,涵盖智能合约开发、去中心化AI模型训练与推理、数据隐私保护以及通证经济激励等核心主题。我们将完整展示从区块链基础集成、智能合约编写、AI模型上链到去中心化应用(DApp)开发的全流程,为构建下一代可信、透明的智能去中心化系统提供完整技术方案。
223 3
|
1月前
|
机器学习/深度学习 人工智能 监控
Java与AI模型部署:构建企业级模型服务与生命周期管理平台
随着企业AI模型数量的快速增长,模型部署与生命周期管理成为确保AI应用稳定运行的关键。本文深入探讨如何使用Java生态构建一个企业级的模型服务平台,实现模型的版本控制、A/B测试、灰度发布、监控与回滚。通过集成Spring Boot、Kubernetes、MLflow和监控工具,我们将展示如何构建一个高可用、可扩展的模型服务架构,为大规模AI应用提供坚实的运维基础。
226 0
|
1月前
|
人工智能 Java 物联网
Java与边缘AI:构建离线智能的物联网与移动应用
随着边缘计算和终端设备算力的飞速发展,AI推理正从云端向边缘端迁移。本文深入探讨如何在资源受限的边缘设备上使用Java构建离线智能应用,涵盖从模型优化、推理加速到资源管理的全流程。我们将完整展示在Android设备、嵌入式系统和IoT网关中部署轻量级AI模型的技术方案,为构建真正实时、隐私安全的边缘智能应用提供完整实践指南。
260 3
|
安全 JavaScript Java
构建 Java 镜像的 10 个最佳实践
构建 Java 镜像的 10 个最佳实践
|
存储 安全 Java
构建Java镜像的10个最佳实践
构建Java镜像的10个最佳实践
构建Java镜像的10个最佳实践
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
135 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
156 1
|
2月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案

热门文章

最新文章