2021SC@SDUSC
目录
前言
我负责的部分包括openmeetings-db和openmeetings-core两个模块,我选择首先分析openmeetings-db模块。本文主要对模块的结构进行梳理,开始源码的分析工作。
模块结构
先查看以下openmeetings-db模块的树状结构。操作方法是:打开项目的src目录,即包含所有模块的源码根目录,进入cmd,使用tree openmeetings-db命令查看其树状结构,结果如下:
树状结构的节点只包含了其中的文件夹,没有显示文件。可以清晰地看出,openmeetings-db模块下只有一个src文件夹,即源码文件夹。src目录下,包含了main、site、test三个目录,其中main是存放项目的java文件及资源(这里似乎没有资源,也就没有resources目录),test是存放用来测试的java文件及其资源,site目录中保存了项目将要生成的各html文件等等。
再到目录中看一下其结构:
在openmeetings-db目录下,除了src文件夹,还有openmeetings-db.iml和pom.xml两个文件。其中openmeetings-db.iml是idea自动创建的模块文件,用于java应用开发,存储模块开发相关的信息及模块路径信息等等;pom.xml则是maven项目的核心配置文件,是maven项目必须具备的文件。
因此,接下来的分析首先从pom.xml入手。
pom.xml
基本说明
modelVersion | Maven模型的版本,对于Maven2、Maven3来说,只能是4.0.0 |
groupId | 组织的id,一般是公司域名的倒写。格式可以为: 1、域名倒写。如:com.baidu 2、域名倒写+项目名。如:com.baidu.appolo |
artifactId | 项目名称,也是模块名称,对应groupId中项目的子项目 |
version | 项目的版本号 如果项目还在开发中,版本不稳定,则通常在版本号后加-SNAPSHOT 通常使用3位数字标识,如1.0.0 |
packaging | 项目打包的类型,可选值为jar、war、rar、ear、pom,默认为jar |
dependencies和dependency | Maven的一个重要作用就是管理jar包,为了一个项目可以构建或运行,项目中不可避免要依赖许多其他jar包。在Maven中,这些jar就被称为依赖,使用标签dependency来配置。而这种依赖的配置正是通过坐标来定位的,由此我们也不难看出,maven把所有的jar包都视为项目存在了。 |
properties | properties是用来定义一些配置属性的,例如project.build.sourceEncoding(项目构建源码编码方式),可以设置为UTF-8,防止中文乱码,也可定义相关构建版本号,便于日后统一升级。 |
build | build表示与构建相关的配置,例如设置编译插件的jdk版本。 |
parent | 在Maven中,如果多个模块都需要声明相同的配置,例如:groupId、version,有相同的依赖,或者相同的组件配置等,也有类似Java的继承机制,用parent声明要继承的父工程的pom配置。 |
modules | 在Maven的多模块开发中,为了统一构建整个项目的所有模块,可以提供一个额外的模块,该模块打包方式为pom,并且在其中使用modules聚合的其他模块,这样通过本模块就可以一键自动识别模块间的依赖关系来构建所有模块,叫做Maven的聚合。 |
其中,groupId、artifactId、version三个元素构成了Maven项目的坐标,在众多的Maven项目中可以定位到唯一的项目。
源码分析
使用IDEA打开pom.xml,可以看到源码结构如下:
附上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>
<parent>
<groupId>org.apache.openmeetings</groupId>
<artifactId>openmeetings-parent</artifactId>
<version>4.0.7</version>
<relativePath>..</relativePath>
</parent>
<artifactId>openmeetings-db</artifactId>
<packaging>jar</packaging>
<name>Openmeetings DB</name>
<description>OpenMeetings module for all Database/DTO related classes</description>
<properties>
<site.basedir>${project.parent.basedir}</site.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.openmeetings</groupId>
<artifactId>openmeetings-util</artifactId>
</dependency>
<dependency>
<groupId>org.wicketstuff</groupId>
<artifactId>wicketstuff-datastore-hazelcast</artifactId>
<version>${wickets.version}</version>
</dependency>
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>${openjpa.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.simpleframework</groupId>
<artifactId>simple-xml</artifactId>
</dependency>
<dependency>
<groupId>org.asteriskjava</groupId>
<artifactId>asterisk-java</artifactId>
<version>${asterisk-java.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${commons-dbcp.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>${commons-pool.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${commons-pool2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>${derby.version}</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
<version>${derby.version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.version}</version>
</dependency>
<dependency>
<groupId>org.apache.openmeetings</groupId>
<artifactId>openmeetings-util</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa-maven-plugin</artifactId>
<version>${openjpa.version}</version>
<configuration>
<includes>**/entity/**/*.class</includes>
<addDefaultConstructor>true</addDefaultConstructor>
<enforcePropertyRestrictions>true</enforcePropertyRestrictions>
<persistenceXmlFile>
${project.parent.basedir}/openmeetings-web/src/main/webapp/WEB-INF/classes/META-INF/derby_persistence.xml
</persistenceXmlFile>
</configuration>
<executions>
<execution>
<id>enhancer</id>
<phase>process-classes</phase>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<!-- set the version to be the same as the level in your runtime -->
<version>${openjpa.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
最开始的xml、project标签都是基础的配置,没有什么好说的。在project标签内,第一个出现的子标签是modelVersion标签,显示Maven模型的版本号为4.0.0,按前文描述也是固定值。
接下来是parent标签,即继承。在parent标签内部,通过groupId、artifactId、version表明了父工程的pom坐标,即总的openmeetings项目,这样就可以直接引用到父工程openmeetings的依赖了。既然写了parent标签,那么紧接着,本模块的坐标中与parent相同的部分就可以省略。如图,坐标只给出了artifactId,并未给出groupId、version。原因是,本模块的groupId和version与父工程的groupId和version相同,如果再次写出的话会警告重复,而artifactId与父工程不同,故而给出。
packaging标签规定了打包类型为jar,接着的name、description标签就没有什么特别的了。
再接下来,是properties标签。在其中,设置了site.basedir,类似于声明一个变量名称为site.basedir,也就是配置一个自定义的属性,可在其他地方使用,使用形式是${}。而site.basedir的值为${project.parent.basedir},也就是父工程的位置。
这里需要插一些关于pom中properties标签的内容。在pom中的properties标签,下面可以自定义Maven属性,定义格式为<标签>值</标签>,可以使用${}格式来使用在properties里定义的属性。
一些常用的例子:
1、所有pom中的元素都可以用 project,例如例如${project.artifactId}对应了<project><artifactId>元素的值。
2、常用的POM属性:
1)${basedir} 表示项目根目录,即包含pom.xml文件的目录
2)${version} 等同于 ${project.version} 表示项目版本
3)${project.build.directory}:项目构建输出目录,默认为target
4)${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}${project.version}
5)所有环境变量都可以使用以env.开头的Maven属性所引用。例如,${env.JAVA_HOME}指代JAVA_HOME环境变量的值
再接下来,就是dependencies标签。前文介绍了,pom使用dependencies和dependency配置依赖。展开dependencies标签,可以看到:
dependencies标签里由dependency标签组成,每个dependency标签又指明了该依赖对应的坐标。标签形式类似,由于篇幅有限,就不再展开赘述了。
最后是build标签,它表述了与构建相关的配置。展开它的源码如下:
此处关于build标签的作用,参考自博文https://blog.csdn.net/jiachunchun/article/details/90235498
关于build标签的作用,详细来说,是描述了项目的编译及打包,具体工作通过其中的plugin配置来完成。但注意,plugin不是必须的,即时不添加plugin也会默认引入以下插件:
其余详细说明可在Maven官网(Maven – Welcome to Apache Maven)查询,关于Maven提供的插件也可在Maven – Available Plugins查找对应信息直接使用。
在这里的build标签中,指明了需要的plugin,相应的配置也不再多说。
以上便是pom.xml的内容分析。
src目录结构
说明
根据前文的说明,src目录下存放的是模块的源码,其中的main目录下存放的是项目正式的java文件及其资源,test目录下存放的是测试的java文件及其资源。因此分析工作主要针对main目录,辅之以对test目录的分析。
main目录结构
根据前文的树结构和标准的Maven项目结构,main/java目录下即存放java源代码,它的结构为main/java/org/apache/openmeetings,然后openmeetings目录结构如下:
起初我不理解为什么main/java目录下仍然嵌套了许多层目录,因此首先要明确,在这里,任何一个java文件所在的目录的路径都包含了它的包名。例如IApplication.java文件,其所在目录为:
其包名应该是从java目录往后的部分,即org.apache.openmeetings。打开其源码,果然如此:
同样,对于在db目录下的java文件,db也包含在其包名内。
在main/java目录下的java文件之间,既存在对源码中其他的类的引用,也存在对项目所依赖的jar包中类的引用,仍以IApplication.java为例:
它引用了源码中的org.apache.openmeetings.db.dao.basic中的ConfigurationDao.java中的类,它来自源码中同样的java文件;也引用了org.apache.wicket.request等中的类,它来自整个Maven项目所依赖的jar包。这可以在IDEA中的External Libraries中查看:
External Libraries是IDEA根据项目的依赖生成了iml文件后,对应的全部依赖。
弄清楚了这个问题,就可以在接下来的分析中快速理清各文件之间的引用关系,分析源码的逻辑了。
总结
本文分析了openmeetings-db的源码结构,对pom.xml进行了分析,还对java文件的相互引用关系作了初步阐述。接下来的任务,就是择定一个文件为入口,逐步展开对src目录的分析工作。