【问题标题】:Maven beginner questions - though somewhat a complex project setupMaven 初学者问题——虽然项目设置有点复杂
【发布时间】:2011-01-18 07:27:03
【问题描述】:

因此,我将自己归类为几乎没有 Java 经验的高级开发人员。我正在开发一个小宠物项目,它基本上是一个桌面应用程序,带有用于插件的 sdk,以及一组插件,只要它们实现了 sdk 中定义的接口,应用程序就会加载这些插件。它看起来像这样:

项目结构

main-app
|---pom.xml (depends on <sdk>)
|---src
    |---[com.etc…]
|---target
    |---main-app.jar (does this include sdk.jar?)


sdk
|---pom.xml
|---src
    |---[com.etc…]
        |---IPlugin (public interface IPlugin)
|---target
    |---sdk.jar

(sdk - defines the interface that plugins need to implement)


plugins
|---plugin1
    |---pom.xml (depends on <sdk>)
    |---src
        |---[com.etc…]
    |---target
        |---plugin1.jar

plugin1 is a plugin that implements IPlugin interface and has the following classpath
<com.foo.plugin1>

deploy
|---app.folder
    |---main-app.jar
    |---sdk.jar
    |---plugins.folder
        |---plugin1.jar


在应用程序启动时,main.app 解析 plugins.folder 并打开每个 jar 文件 - 在清单中查找一个元素,该元素指定实现 IPlugin 接口的插件的类路径。

我遇到了几个 maven/jar 概念......

  • 我的部署文件夹目前是幻想。它不存在。我没有知识让它存在。目前我在每个子项目(或在 IntelliJ 中调用的模块)中有一个单独的 JAR 文件
  • main-app.jar 中是否必须包含 sdk 类?
  • 如果没有,我如何部署 main-app.jar 以便它知道 sdk.jar,以及我将 sdk.jar 放在哪里?
  • 有没有办法将自定义字段添加到 plugin1 jar 清单文件中,我可以在其中指定主应用的类路径以将其与 IPlugin 接口相关联?

到目前为止,我的 pom.xml 文件非常简单。它们基本上定义了 groupID、artifactID 和打包类型 (JAR) 以及它们的依赖关系。就是这样。

目前主应用程序(无插件)在 IntelliJ 中成功构建和运行 - 但这对部署打包完全没有帮助。

编辑:

只是为了清楚... main-app 和 sdk 在开发过程中构建和部署。 plugin1 由第三方添加到 plugins.folder 中。第三方开发者如何使用 maven 在 plugin.jar 清单文件中指定他们的类路径?

【问题讨论】:

    标签: java plugins jar maven


    【解决方案1】:

    如果 main_app 不是 Web 应用程序并且依赖于其他 jar,并且如果您需要 distribute 它,那么执行此操作的一种方法是创建一个程序集(例如 .zip 或 .tar.gz 文件)其中包括 main_app.jars 和依赖的 jars。 Maven Assembly Plugin 可以帮你做到这一点。

    您可以使用 Maven Jar Plugin 进行清单自定义

    【讨论】:

    • 我想这就是我要找的东西......确实,它不是一个网络应用程序 - 它是一个桌面应用程序,将按原样分发......
    【解决方案2】:

    我可能没有理解你的问题。但看起来你想要实现的目标是微不足道的。你的主应用程序依赖于另外两个模块。因此,您只需要在引用子模块的主应用程序项目中添加依赖项标签。 (我将把范围留空)。

    假设你的插件模块的 pom 是这样的。

    <groupId>om.foo.plugin1</groupId>
    <artifactId>plugin1</artifactId>
    <version>1.0</version>
    

    在主模块中添加相应的依赖标签即可。

    <dependency>
        <groupId>om.foo.plugin1</groupId>
        <artifactId>plugin1</artifactId>
        <version>1.0</version>
    </dependency>
    

    只是一件小事,需要先使用 mvn clean install 构建依赖项,然后才能构建父级。

    【讨论】:

    • 当你运行 mvn install 时,你的 jar 将被安装到你本地的 maven 仓库中,其他模块可以引用它..
    【解决方案3】:

    说实话,这是一个相当大的构建,我使用了一些最佳实践来保持所有这些东西井井有条。

    首先,我将您的代码划分为几个模块,并将其布局如下:

    pom.xml
    /src
        /app
            /app-name
                pom.xml
                /src ...
            /app-name-sdk
                pom.xml
                /src ...
            /deployment
                pom.xml
                /src
                    /assembly
                        image.xml
                    /main
                        /app-folder
                            /bin
                                startup-script.sh
                                startup-script.bat
                            /etc
                                config.conf
                                ...
        /plugins
            /plugin-A
                pom.xml
                /src ...
            /plugin-B
                pom.xml
                /src ...
    

    此时,您已在逻辑上分离出所有不同的组件部分,清楚地知道所有内容的位置,并打包成逻辑组。 (现在当我再次检查它时,它看起来不像是文件夹呕吐物,因为我现在可以将 /doc 和 /bin 目录保留在顶层,并且知道 /src 下的子目录描述了每个相关子模块中的内容。)

    此时,顶层 pom.xml 应大致如下所示:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>app-name-parent</artifactId>
        <groupId>com.mycompany.my-app</groupId>
        <version>1.3.2-SNAPSHOT</version>
        <packaging>pom</packaging>
    
        <name>[Parent]  My App</name>
    
        <modules>
            <!-- App -->
            <module>src/app/app-name</module>
            <module>src/app/my-app-sdk</module>
    
            <!-- Plugins -->
            <module>src/plugins/plugin-A</module>
            <module>src/plugins/plugin-B</module>
    
            <!-- Packaging -->
            <module>src/app/distribution</module>
        </modules>
    
        <properties>
            <!-- Useful properties to define here -->
            <scm.revision>USER</scm.revision>
            <compiler.debug>true</compiler.debug>
            <compiler.optimize>false</compiler.optimize>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    
            <!-- If you're not going to version your plugins with the parent,
                 then you should pick out the specific version info here 
                 for each plugin.  That way, you could just update individual plugins.
                 If this is to be packaged up and shipped together, it's probably not necessary.
            -->
            <plugin-A.version>1.1</plugin-A.version>
            <plugin-B.version>1.3</plugin-B.version>
        </properties>
    
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>2.3</version>
                        <configuration>
                            <source>1.6</source>
                            <target>1.6</target>
                            <debug>${compiler.debug}</debug>
                            <optimize>${compiler.optimize}</optimize>
                            <fork>true</fork>
                        </configuration>
                    </plugin>
                    <plugin>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>2.5</version>
                        <configuration>
                            <includes>
                                <include>**/*Test.java</include>
                            </includes>
                        </configuration>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    
        <dependencyManagement>
            <dependencies>
    
                <!-- Test Dependencies -->
                <dependency>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                    <version>4.3.1</version>
                    <scope>test</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <profiles>
            <profile>
                <id>release</id>
    
                <properties>
                    <compiler.debug>false</compiler.debug>
                    <compiler.optimize>true</compiler.optimize>
                </properties>
            </profile>
    
            <profile>
                <id>ci-server</id>
    
                <activation>
                    <property>
                        <name>env.SVN_REVISION</name>
                    </property>
                </activation>
    
                <properties>
                    <scm.revision>${env.SVN_REVISION}</scm.revision>
                </properties>
            </profile>
        </profiles>
    </project>
    

    然后,您的所有子模块都需要定义到父模块的链接,如下所示:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <artifactId>app-name-parent</artifactId>
            <groupId>com.mycompany.my-app</groupId>
            <version>1.3.2-SNAPSHOT</version>
            <relativePath>../../..</relativePath>
        </parent>
    
        <groupId>com.mycompany.my-app</groupId>
        <artifactId>app-name</artifactId>
    
        <name>[App]    My App</name>
        <description>
            TODO
        </description>
    
        <dependencies>
             <!-- System dependencies -->
            <dependency>
                <groupId>${project.parent.groupId}</groupId>
                <artifactId>app-name-sdk</artifactId>
                <version>${project.version}</version>
            </dependency>
    
            <!-- Test Dependencies -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

    为了这个世界上所有神圣和正确的事物的爱,不要尝试将所有内容打包到与 jar 输出相关的模块之一中。这是错误的,所有这样做的人都是分流

    我在开玩笑。

    但说真的:将打包过程分解为自己的单独模块,这里是 src/app/deployment 模块,用于打包构建的其他工件。然后,它实际上只依赖于系统中的其他组件,并且可能看起来像:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <artifactId>app-name-parent</artifactId>
            <groupId>com.mycompany.my-app</groupId>
            <version>1.3.2-SNAPSHOT</version>
            <relativePath>../../..</relativePath>
        </parent>
    
        <groupId>com.mycompany.my-app</groupId>
        <artifactId>deployment</artifactId>
        <packaging>pom</packaging>
    
        <name>[App]     Deployment Image</name>
        <description>
            TODO
        </description>
    
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>image</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                            <configuration>
                                <tarLongFileMode>gnu</tarLongFileMode>
                                <descriptors>
                                    <descriptor>src/assembly/image.xml</descriptor>
                                </descriptors>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    
        <dependencies>
            <dependency>
                <groupId>${project.parent.groupId}</groupId>
                <artifactId>my-app</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <!-- Notice the separate group namespace element 'plugins', for clarity -->
                <groupId>${project.parent.groupId}.plugins</groupId>
                <artifactId>plugin-A</artifactId><!-- Or project.version, depending... -->
                <version>${plugin-A.version}</version>
            </dependency>
            <dependency>
                <groupId>${project.parent.groupId}.plugins</groupId>
                <artifactId>plugin-B</artifactId>
                <version>${plugin-B.version}</version><!-- Or project.version, depending... -->
            </dependency>
        </dependencies>
    </project>
    

    然后您可以使用程序集描述符文件(此处为 image.xml)将所有内容打包成一个连贯的整体,如下所示:

    <assembly>
        <id>image</id>
        <formats>
            <format>tar.gz</format>
        </formats>
        <includeBaseDirectory>false</includeBaseDirectory>
    
        <dependencySets>
            <!--  Everything  -->
            <dependencySet>
                <outputDirectory>/app-folder/jars</outputDirectory>
                <useProjectArtifact>false</useProjectArtifact>
                <fileMode>0644</fileMode>
                <directoryMode>0644</directoryMode>
                <!-- This includes all transitive, <scope>compile</scope> dependencies -->
    
                <includes>
                    <include>${project.parent.groupId}:*</include>
                </includes>
            </dependencySet>
        </dependencySets>
    
        <!--  Packaged scripts, config files, etc.  -->
        <fileSets>
            <fileSet>
                <outputDirectory>/app-folder/bin</outputDirectory>
                <lineEnding>unix</lineEnding>
                <fileMode>0755</fileMode>
                <directoryMode>0744</directoryMode>
                <filtered>false</filtered>
    
                <directory>src/main/app-folder/bin</directory>
                <includes>
                    <include>**/*</include>
                </includes>
    
                <!--  Some weird files are added here, for some reason  -->
                <excludes>
                    <exclude>*.*.formatted</exclude>
                </excludes>
            </fileSet>
            <fileSet>
                <outputDirectory>/app-folder/etc</outputDirectory>
                <lineEnding>unix</lineEnding>
                <fileMode>0640</fileMode>
                <directoryMode>0744</directoryMode>
                <filtered>true</filtered>
    
                <directory>src/main/app-folder/etc</directory>
                <includes>
                    <include>**/*</include>
                </includes>
    
                <!--  Some weird files are added here, for some reason  -->
                <excludes>
                    <exclude>*.*.formatted</exclude>
                </excludes>
            </fileSet>
        </fileSets>
    </assembly>
    

    您可以通过包装获得更精美的包装,但这是让您完成 90% 的基本原理。

    很抱歉这篇文章的长度,但我这样做很多,遵循这种做法确实让一切变得更清晰,更容易弄清楚,特别是如果我必须在几个月后回来.

    【讨论】:

      猜你喜欢
      • 2011-08-25
      • 2022-01-12
      • 1970-01-01
      • 2017-07-31
      • 2010-10-10
      • 1970-01-01
      • 2014-10-24
      • 2015-08-21
      • 1970-01-01
      相关资源
      最近更新 更多