配置Maven项目自动编译

Author: ChinSyun Pang
Weibo: arthinking_plus
Posted in: http://www.itzhai.com

Maven项目目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
project
- src
- main
- java
- resources
- webapp
- WEB-INF
- classes
- lib
- target
- project-snapshot
- WEB-INF
- classes
- lib
- classes
```
其中 project-snapshot就是maven编译生成的项目目录了,我们一般使用这个目录对项目进行部署,这样问题来了:

每次改动JSP文件或者Java文件,都得重新用maven编译一下,以便生成代码到该目录,有没有方便点的做法呢?接下来就是啦。

## 让Maven项目自动编译:

为了让改写JSP之后无需重新编译,我们只有使用src/main/webapp/这个目录进行部署了,因为一般我们是直接改动里面的文件进行编码的;

而jar包是maven从仓库下载过来的,为了能用上下载回来的jar包,我们可以把
> target/project-snapshot/WEB-INF/lib

目录联接到

> src/main/webapp/WEB-INF/lib

windows下通过 [mklink /j](http://technet.microsoft.com/en-us/library/cc753194.aspx "mklink") 命令(假设项目在D:/dev目录下):

mklink /j “D:\dev\project\src\main\webapp\WEB-INF\lib” “D:\dev\project\target\project-snapshot\WEB-INF\lib”

1
2
3
4
5
6
7
8
9
10
11

这样就把maven下载的lib目录联接到部署目录webapp下了;

对于class目录,也是同样的方法,另外需要设置IDE的自动编译输出目录到:
> target/project-snapshot/WEB-INF/classes

右击项目 -> properties -> Java Build Path -> 右边面板底部设置Default output folder;

## 直接运行main方法的问题

但是这样Eclipse下会有个问题,直接运行某个类的main方法,会提示如下错误:

java.lang.NoClassDefFoundError: me/arthinking/test/Demo
Caused by: java.lang.ClassNotFoundException: me.arthinking.test.Demo
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Exception in thread “main”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
原因是没有读取到输出的classes文件,为此,我们可以把class编译输出目录设置为:    

> project/target/classes

这样就可以正常执行main方法了

把这个目录联接到webapp/WEB-INF/classes目录下即可。
编译目录设置如图:
![](https://raw.githubusercontent.com/arthinking/informal-essay/master/images/2014/12/20141204-java01.png)

其他的配置文件目录需要联接到webapp目录,同上操作。



## 关于IDEA集成开发环境

据[Ryan](https://github.com/mojunbin "Ryan")介绍,IDEA集成开发环境是不会存在找不到main方法的问题的;

另外我们也可以在pom.xml中配置classes文件的输出目录,把classes文件输出到webapp目录下,这样改写了Java文件之后需要使用maven编译下项目了。:sunglasses:
pom.xml
```xml
<outputDirectory>D:\dev\project\webapp\WEB-INF\classes</outputDirectory>

Resin中的配置

现在我用着Resin,恰巧,resin里面提供了一个 的配置标签,通过其中的 子标签同样可以配置加载class文件和jar包的位置,配置代码如下:

1
2
3
4
5
6
7
8
<web-app id="/" root-directory="D:\dev\project\src\main\webapp">
<prologue>
<class-loader>
<compiling-loader path="D:\dev\project\target\classes"/>
<library-loader path="D:\dev\project\target\project-snapshot\WEB-INF\lib"/>
</class-loader>
</prologue>
</web-app>

进一步查看官方文档可以发现有这样的介绍:

automatically compiles Java code into .class files before loading them.

首先这里class-loader实现了热部署(类似的一般的Servlet容器都提供了JSP的加载器,如Tomcat的JasperLoader,当容器检测到JSP文件被修改的时候,会自动替换掉原来的JSP加载器的Class实例,并创建一个新的,从而实现热部署。关于Resin中的类加载器执行问题),那么如果会在加载class文件之前重新编译源代码,就需要提供源代码的目录,查看文档,可以发现source这样的一个属性,添加上之后配置如下:

1
<compiling-loader path="D:\dev\project\target\classes" source="D:\dev\project\src\main\java"/>

这样就会在加载class前先自动编译Java代码了,这对于Eclipse没有开启自动编译功能的环境尤其有用(Eclipse的自动编译功能也是需要一定的资源开销的,有时候会导致Eclipse卡住,如果关闭了该功能,可以尝试以上配置)。

其他的热部署方案

热部署神器JRebel

这里是JRebel和JVM Hot Swap的区别

另外,这里有一个JVM hotswap的补丁

说到HotSwap特性,是在2002年的时候,Sun在Java 1.4的JVM中引入的实验性技术。这一技术被合成到了DebuggerAPI的内部。
《HotSwap和JRebel——幕后的故事》

Resin中的热部署

在resin.conf中添加如下的JVM启动参数:

1
<jvm-arg>-Xdebug</jvm-arg>

表示启动debug模式,当更新了类中的方法的时候,控制台会提示reloading class,这是通过JVM的HotSwap功能动态更新的。

1
... Reloading ...

由于JVM的HotSwap不支持新增属性,方法和类的修改,所以进行了这些操作之后,是无法实现热部署的,Resin会自动改用Hot deploy的方式进行应用更新。

当去掉该启动参数的时候,修改一个类,控制台会提示如下的内容:

1
2
... WebApp[...] stopping
... WebApp[...] active

发表于:http://www.itzhai.com/maven-setting-auto-compile.html