Maven有哪些优点和缺点

本文详细介绍了Maven的相关知识,包括其优缺点、坐标、依赖范围、生命周期等。阐述了‘Mvn Clean Package’命令执行的动作,还讲解了依赖和插件的解析机制,以及多模块聚合、依赖版本管理、避免传递依赖冲突等内容,最后介绍了Maven私服仓库类型和查询插件目标的方法。

一、Maven有哪些优点和缺点

优点如下:

  1. 简化了项目依赖管理:
  2. 易于上手,对于新手可能一个"mvn clean package"命令就可能满足他的工作
  3. 便于与持续集成工具(jenkins)整合
  4. 便于项目升级,无论是项目本身升级还是项目使用的依赖升级。
  5. 有助于多模块项目的开发,一个模块开发好后,发布到仓库,依赖该模块时可以直接从仓库更新,而不用自己去编译。
  6. maven有很多插件,便于功能扩展,比如生产站点,自动发布版本等

缺点如下:

  1. maven是一个庞大的构建系统,学习难度大
  2. maven采用约定优于配置的策略(convention over configuration),虽然上手容易,但是一旦出了问题,难于调试。
  3. 当依赖很多时,m2eclipse 老是搞得Eclipse很卡。
  4. 中国的网络环境差,很多repository无法访问,比如google code, jboss 仓库无法访问等。

二、Maven坐标

一般maven使用[groupID,artifactId,version,packaging]来表示一个项目的某个版本,有时还会使用classifier来表示项目的附属构建,常见的附属构建有javadoc和sources包。

三、Maven常见的依赖范围有哪些?

  1. compile:编译依赖,默认的依赖方式,在编译(编译项目和编译测试用例),运行测试用例,运行(项目实际运行)三个阶段都有效,典型地有spring-core等jar。
  2. test:测试依赖,只在编译测试用例和运行测试用例有效,典型地有JUnit。
  3. provided:对于编译和测试有效,不会打包进发布包中,典型的例子为servlet-api,一般的web工程运行时都使用容器的servlet-api。
  4. runtime:只在运行测试用例和实际运行时有效,典型地是jdbc驱动jar包。
  5. system: 不从maven仓库获取该jar,而是通过systemPath指定该jar的路径。
  6. import: 用于一个dependencyManagement对另一个dependencyManagement的继承。

四、Maven的生命周期

maven有三套生命周期,分别为:

1、clean 周期:主要用于清理上一次构建产生的文件,可以理解为删除target目录

2、默认周期,
主要阶段包含:

  1. process-resources 默认处理src/test/resources/下的文件,将其输出到测试的classpath目录中,
  2. compile 编译src/main/java下的java文件,产生对应的class,
  3. process-test-resources 默认处理src/test/resources/下的文件,将其输出到测试的classpath目录中,
  4. test-compile 编译src/test/java下的java文件,产生对应的class,
  5. test 运行测试用例,
  6. package 打包构件,即生成对应的jar, war等,
  7. install将构件部署到本地仓库,
  8. deploy 部署构件到远程仓库

3、site周期

主要阶段包含

  • site 产生项目的站点文档
  • site-deploy 将项目的站点文档部署到服务器

五、我们经常使用“Mvn Clean Package”命令进行项目打包,请问该命令执行了哪些动作来完成该任务?

在这个命令中我们调用了maven的clean周期的clean阶段绑定的插件任务,以及default周期的package阶段绑定的插件任务
默认执行的任务有(maven的术语叫goal, 也有人翻译成目标,我这里用任务啦):

  • maven-clean-plugin:clean->
  • maven-resources-plugin:resources->
  • maven-compile-plugin:compile->
  • mavne-resources-plugin:testResources->
  • maven-compile-plugin:testCompile->
  • maven-jar-plugin:jar

六、依赖的解析机制

  1. 解析发布版本:如果本地有,直接使用本地的,没有就向远程仓库请求。
  2. 解析快照版本:合并本地和远程仓库的元数据文件-groupId/artifactId/version/maven-metadata.xml,这个文件存的版本都是带时间戳的,将最新的一个改名为不带时间戳的格式供本次编译使用。
  3. 解析版本为LATEST,RELEASE,过于复杂,且解析的结果不稳定, 不推荐在项目中使用,感兴趣的同学自己去研究,简而言之就是合并groupId/artifactId/maven-metadata.xml找到对应的最新版本和包含快照的最新版本。

七、插件的解析机制

当我们输入"mvn dependency:tree"这样的指令,解析的步骤为:
解析groupID:
maven使用默认的groupID:"org.apache.maven.plugins"或者"org.codehaus.mojo"
解析artifactId(maven的官方叫做插件前缀解析策略)
合并该groupId在所有仓库中的元数据库文件(maven-metadata-repository.xml),比如maven官方插件的元数据文件所在的目录为org\apache\maven\plugins,该文件下有如下的条目

通过比较这样的条目,我们就将该命令的artifactId解析为maven-dependency-plugin
解析version
如果你在项目的pom中声明了该插件的版本,那么直接使用该版本的插件,否则合并所有仓库中groupId/artifactId/maven-metadata-repository.xml,找到最新的发布版本。

对于非官方的插件,有如下两个方法可以选择:
1)使用groupId:artifactId:version:goal 来运行,好长~~~~~~~~~~
2)在Settings.xml中添加pluginGroup项,这样maven不能在官方的插件库中解析到某个插件,那么就可以去你配置的group下查找啦。

八、多模块如何聚合

配置一个打包类型为pom的聚合模块,然后在该pom中使用<module>元素声明要聚合的模块

九、对于一个多模块项目,如果管理项目依赖的版本

通过在父模块中声明dependencyManagement和pluginManagement, 然后让子模块通过<parent>元素指定父模块,这样子模块在定义依赖是就可以只定义groupId和artifactId,自动使用父模块的version,这样统一整个项目的依赖的版本。

十、一个项目的依赖来源于不同的组织,可能这些依赖还会依赖别的Jar包,如何保证这些传递依赖不会引起版本冲突。

使用<dependency&gt的<exclusion>元素将会引起冲突的元素排除。

十一、常见的Maven私服的仓库类型。

(宿主仓库)hosted repository, (代理仓库)proxy repository, (仓库组)group repository

十二、如何查询一个插件有哪些目标(Goal)

mvn help:describe -Dplugin=groupId:artifactId

from: http://www.javacoder.cn/?p=211


1.[今日课程内容总览] Maven--***** 介绍 优点 用maven创建一个项目, 用maven创建一个ssm项目,每一层的代码分开,把一个项目拆解成多个项目 2.[今日包含笔记] maven介绍: Eclise: 缺点: Jar包: 版本管理,解决jar包冲突:删除老的jar包,保留新的jar包 不同的项目,jar包要复制一份;Users Library 羡慕yum的好处,安装软件,自动下载,自动验证,自动安装,自动测试;镜像网站 Jar包的依赖: 致命的缺点:现象: 每一个项目都有前台(广大网民)后台(管理员看的),后台的功能远远的大于>前台的功能;迭代升级;每次升级都要重启tomcat;将tomcat做很多个备份(10个),为了nginx转发;前台:访问比较大,管理员访问量比较小; 问题: 每次升级,10个tomcat都升级一次 后台的升级频繁要比前台频繁;升级10次,9次改的是后台的代码,只有一次是前台的代码 解决方案: 是将前台(广大网民看的页面)的代码后台(管理员)的代码要分开,将原来的一个项目分别放到两个web项目;一个web项目一个tomcat;好处:更新的时候如果更新后台(管理员),只需要重启后台的tomcat(服务); 折成两个项目以后的缺点:Service以下的代码重复; 将Service层以下的代码放到一个新创建的java项目中,在部署的时候将Service(java项目)打成一个jar包,分别放到两个web服务中;编译的时候让web项目依赖与Service(java项目)_source folder;配置麻烦,项目项目之间的依赖头脑得相当清晰 这个缺点Maven解决了; 请听今天的内容 拆分前:图一 拆分后是图二 3. 介绍 官网:http://maven.apache.org/download.cgi 目录介绍: Bin:二进制文件 Boot:引导,启动 Conf:配置文件 Lib:jar包 README.txt:读我 3.1.修改配置文件的内容 路径:%MAVEN_HOME%\conf\settings.xml 配置文件代码: d:/repo alimaven aliyun maven http://maven.aliyun.com/nexus/content/groups/public/ central 注意: 千万不要将文档中的setting的内容全部替换到maven中的内容,要对比着修改,保留原来的; 只修改本地仓库,下载镜像(源) 3.2.Eclipse Maven的配置 每打开一个新的工作空间,要配置一下Maven,然后再写代码 3.3.创建Maven项目 右击创建一个maven project Packing:有三种: Jar:java项目, War:web项目 Pom:文件夹,jarwar文件,mavenProject:一个项目,可以放jarwar包,通过pom,一般新创建的maven Project是POM 3.4.创建一个Maven Model 最外面的项目MavenProject,其它的全部是Maven Model 3.4.1.创建JAR 目录介绍: Mvn-jar |-->Src:源码:java代码 |-->|-->main:代码:除测试以外的代码:junit |-->|-->main|-->java:代码 |-->|-->main|-->resources:配置文件 |-->|-->test:测试的代码,junit |-->|-->test|-->java:代码 |-->|-->test|-->resources:配置文件 |-->Target:编译后的文件 |-->|-->classes:代码编译后的class类 |-->|-->test-classes:测试类编译后的classes 3.4.2.创建WAR 目录介绍: Mvn-war |-->Src:源码:java代码 |-->|-->main:代码:除测试以外的代码:junit |-->|-->main|-->java:代码 |-->|-->main|-->resources:配置文件 |-->|-->main|-->webapp:webContent,一般放jsp,js,css |-->|-->test:测试的代码,junit |-->|-->test|-->java:代码 |-->|-->test|-->resources:配置文件 |-->Target:编译后的文件 |-->|-->classes:代码编译后的class类 |-->|-->test-classes:测试类编译后的classes |-->|-->m2e-wtp:编译后的web服务;war解压后的内容 创建war包以后报以下错误: 因为创建的web项目,webapps少了web-inf,web.xml 解决方案: 在项目上右击,Javaee Tools-->第二个选项 3.5.配置编译环境 将maven项目重新编译,在项目中右击,可以pom上右击,可以将pom(目录)下面的jarwar重新编译 如果出现以上情况,说明下载的jar包有问题,把这下面的文件删除,重新下载 每创建一个项目,都有pom.xml,所有的配置都在pom.xml中 网址:所有的groupIdartifactId到这个网站中找 http://mvnrepository.com/ Pom.xml:配置文件示例(含的编译环境) 4.0.0 com.bjsxt mvn 0.0.1-SNAPSHOT pom mvn mvn mvn-jar mvn-war org.apache.maven.plugins maven-surefire-plugin true org.apache.maven.plugins maven-compiler-plugin <!-- 3.6.1 --> 1.7 1.7 UTF-8 org.apache.maven.plugins maven-source-plugin true compile jar org.apache.maven.plugins maven-resources-plugin UTF-8 3.6.生命周期 Maven -build:javac;编译 Maven-install:java先编译,后运行 在项目的target中会生成jar包war包, 在仓库中生成相应的目录,里面的放的是jar包war包 Maven-clean:会把项目中的class文件jar包war包删除 Maven-test:运行所的测试类,取决于位置,必须放到src/test下面;在运行的(install)跳过,运行的时候会执行一遍测试类(花的时间长) 4.创建一个标准的ssm项目 项目介绍: Ssm:项目的顶级目录 ssm_common:jar包,放的是原来src_common下面的代码 ssm_service:pom,文件夹,放了apiimpl的项目 ssm_service_api:jar包,放的是所有Service的接口 ssm_service_impl:jar包,所有Service的实现类 ssm_service_back:管理员后台的web服务 ssm_service_head:前台的服务 凡是依赖:如果都是java项目,会将依赖的项目打成一个jar包放到classpath中, 如果是web项目,会将依赖的项目打成一个jar包,放到web-inf/lib中 特别的图 创建完以后如下图: 添加依赖 5.搭建ssm 5.1.创建数据库 5.2.创建项目:确定项目可以在tomcat上运行 5.3.添加Spring 添加jar包 添加JAR包 增加版本的常量 在不同的项目中可以使用不同的版本-这种情况不允许 添加配置文件 写测试代码 如下图: 结论: ~将原来的原始的项目,变成maven项目 ~相同的代码,不同的环境,将项目跑起来 5.4.添加Mybatis 将service折成了两个项目:service-api,service-impl Service-api;放的是Controller层使用到的对象;Service的接口引用,Util,POJO, Service-impl:放的是调用Dao层的对象; 目前来看:我们的web服务都依赖了api服务impl服务,在将来引用dubbo的时候,web服务只依赖api服务,不依赖Impl
Java 调用 Python 是可行的,但是否“方便”取决于具体的应用场景、技术选型以及集成方式。下面详细介绍 Java 如何调用 Python,常用的实现方法,以及各自的优缺点。 --- ### ✅ 实现方式一:使用 `Runtime` 或 `ProcessBuilder` 执行 Python 脚本 这是最简单直接的方式,通过启动一个外部进程来运行 Python 脚本。 #### 示例代码: ```java import java.io.*; public class PythonCaller { public static void main(String[] args) { try { // 构建命令:python script.py arg1 arg2 ProcessBuilder pb = new ProcessBuilder("python", "hello.py", "Alice"); pb.redirectErrorStream(true); Process process = pb.start(); // 读取 Python 脚本输出 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("Python script exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } ``` 对应的 `hello.py` 文件: ```python import sys name = sys.argv[1] print(f"Hello from Python, {name}!") print("This is a test output.") ``` #### 解释: - 使用 `ProcessBuilder` 启动 Python 解释器并执行 `.py` 文件。 - Java 可以传参给 Python 脚本(通过 `sys.argv`)。 - 输出通过标准输出流返回给 Java 程序。 - 适用于独立任务,如数据处理、机器学习推理等。 --- ### ✅ 实现方式二:使用 **Jython**(不推荐用于现代项目) [Jython](https://www.jython.org/) 是 Python 在 JVM 上的实现,可以直接在 Java 中调用 Python 代码。 #### 示例代码(Jython): ```java import org.python.util.PythonInterpreter; import org.python.core.*; public class JythonExample { public static void main(String[] args) { try (PythonInterpreter py = new PythonInterpreter()) { py.exec("print('Hello from Jython!')"); py.set("x", new PyInteger(42)); py.exec("y = x + 10"); PyObject y = py.get("y"); System.out.println("y = " + y.toString()); } } } ``` > 注意:需要引入 `jython-standalone` 依赖(Maven): ```xml <dependency> <groupId>org.python</groupId> <artifactId>jython-standalone</artifactId> <version>2.7.3</version> </dependency> ``` #### 缺点: - **仅支持 Python 2.7**,无法使用 Python 3 的语法库(如 TensorFlow、PyTorch、pandas 等)。 - 社区维护缓慢,功能受限。 - 性能不如原生 CPython。 ✅ 优点是完全嵌入 JVM,无缝交互对象。 ❌ 因此 **不推荐用于生产环境**,尤其是涉及现代 Python 库时。 --- ### ✅ 实现方式三:通过 **REST API / Flask/FastAPI 封装 Python 服务** 将 Python 功能封装为 Web 接口,Java 通过 HTTP 调用。 #### Python 服务示例(Flask): ```python from flask import Flask, request, jsonify app = Flask(__name__) @app.route("/greet", methods=["POST"]) def greet(): data = request.json name = data.get("name", "World") return jsonify({"message": f"Hello, {name} from Python!"}) if __name__ == "__main__": app.run(port=5000) ``` #### Java 调用代码(使用 OkHttp 或 HttpURLConnection): ```java import okhttp3.*; public class ApiService { private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private final OkHttpClient client = new OkHttpClient(); private final String url = "http://localhost:5000/greet"; public void callPythonService() throws IOException { String json = "{\"name\": \"JavaApp\"}"; RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() .url(url) .post(body) .build(); try (Response response = client.newCall(request).execute()) { if (response.isSuccessful() && response.body() != null) { System.out.println(response.body().string()); } else { System.err.println("Error: " + response.code()); } } } public static void main(String[] args) throws IOException { new ApiService().callPythonService(); } } ``` #### 优点: - 完全解耦,语言无关。 - 支持复杂数据结构(JSON/XML)。 - 易于扩展、部署、监控。 - 可以利用成熟的 Python 框架(如 FastAPI、Flask、Django)。 #### 缺点: - 需要额外启动服务,增加运维成本。 - 存在网络延迟、序列化开销。 - 需处理异常、超时、重试等。 --- ### ✅ 实现方式四:使用 **Py4J**(推荐用于深度集成) [Py4J](https://www.py4j.org/) 允许 Java Python 在同一台机器上进行跨语言通信。Python 启动一个 gateway server,Java 连接它并调用其函数。 #### Python 端代码(gateway_server.py): ```python from py4j.java_gateway import JavaGateway, GatewayServer class MathOperations: def add(self, a, b): return a + b def multiply(self, a, b): return a * b class Java: # Magic for Py4J exposure implements = ["com.example.MathOperations"] if __name__ == "__main__": gateway = GatewayServer(MathOperations(), port=25333) print("Gateway Server started on port 25333") gateway.start() ``` #### Java 接口定义(可选): ```java package com.example; public interface MathOperations { double add(double a, double b); double multiply(double a, double b); } ``` #### Java 调用端: ```java import py4j.GatewayServer; public class Py4JClient { public static void main(String[] args) { GatewayServer gatewayServer = new GatewayServer(null, 25333); MathOperations math = (MathOperations) gatewayServer.getPythonServerEntryPoint(new String[]{"com.example.MathOperations"}); System.out.println("Add: " + math.add(3.5, 4.5)); // 输出 8.0 System.out.println("Multiply: " + math.multiply(3, 4)); // 输出 12.0 } } ``` > 需安装 Py4J:`pip install py4j` #### 优点: - 实现近乎本地方法调用。 - 支持双向调用(Java ←→ Python)。 - 支持复杂对象传递(需注意类型映射)。 - 比进程通信更高效。 #### 缺点: - 配置稍复杂。 - 需确保 Python 服务常驻或自动重启。 - 不适合高并发场景(单线程默认)。 --- ## ✅ 总结:各种方式对比 | 方法 | 是否推荐 | 优点 | 缺点 | |------|----------|------|--------| | `Runtime/ProcessBuilder` | ⭐⭐⭐☆ | 简单易用,无需依赖 | 启动慢,难传复杂对象,错误处理弱 | | Jython | ❌ | 完全集成 JVM | 不支持 Python 3,生态落后 | | REST API | ⭐⭐⭐⭐⭐ | 解耦好,跨平台,易维护 | 多一层服务,有网络开销 | | Py4J | ⭐⭐⭐⭐ | 高效、支持对象传递 | 需维护 gateway,学习曲线略高 | --- ## 🏁 建议选择策略: - 如果只是偶尔调用脚本 → 用 `ProcessBuilder` - 如果要频繁交互且在同一主机 → 用 **Py4J** - 如果是微服务架构 → 用 **REST API** - 如果想避免外部依赖 → 不要用 Jython(已过时) --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值