一个java项目要最终能提供给用户使用,需要经过两个过程:
- java文件通过”javac命令”编译成class文件。
- class文件通过”java命令”解释成某平台上的机器码并运行。
而如果是一个java web项目,还需再经过一个过程:
- 将class文件和相关资源文件(包括jsp文件、html/js/css文件、图片等)部署到web容器中。
这些过程牵扯到许多编译和运行的细节,本文就简单讨论一下各个过程中涉及到的java编译和运行的一些事儿。
一、最初的javac命令、java命令
java文件又可称java源文件,并通过”javac命令”编译java文件,我们可以认为执行”javac命令”就是在使用java编译器;
class文件又可称java类文件,并通过”java命令”运行class文件,我们可以认为执行”java命令”就是在使用java虚拟机。
如今使用IDE的话基本上是不会再亲手执行这些命令了,但IDE的编译和运行其实也是在帮我们执行类似的这些命令罢了,这些命令原本麻烦的配置也转化成IDE便捷的可视化配置。
java编译器总是在当前的目录中查找文件,但java虚拟机只会在查找在classpath中的文件,并且仅在classpath中有”.”目录时才会查看当前目录。
1.1、java编译器
两个编译机制:
- 执行 javac Employee*.java,所有与通配符匹配的当前目录下的java文件都会被编译成class文件;
- 执行 javac EmployeeTest.java,可能并不仅仅只编译了一个java文件,若EmployeeTest.java中使用了其他的类,则编译器会自动搜索该类并把这个类也编译了。
自动更新机制:
- 编译时,会先查找java文件对应的class文件,若class文件存在,且两者版本一致,则编译器不再编译该java文件;反之,编译器会重新编译该java文件并覆盖掉原先的class文件。
1.2、java虚拟机
执行 java EmployeeTest.java,会先实例化一个EmployeeTest对象(故而会先执行类中的初始化块),再立刻执行 public static void main方法。
二、eclipse中的 java build path
eclipse中的 java build path窗口包含了编译路径的配置和classpath的配置。并且这些配置都保存在.classpath文件中。
2.1、eclipse中的编译路径配置
2.2、eclipse中的classpath配置
2.3、eclipse的.classpath文件
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/extLibs"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
其中主要有上面三种主要类型:
- kind=”src” 并且后面紧跟一个 output——这种是自己写的java文件的编译路径
- kind=”output”——这种是自己写的class文件的classpath,并与编译路径的output一致
- kind=”con”——这种是引用的第三方jar包的classpath
三、eclipse中的 java compiler
上一章只讲了编译路径的配置,但还没有说明会使用哪里的、什么版本的java编译器。首先须明确一点:在eclipse中编译用的是eclipse内嵌自带的编译器——eclipse JDT。所以使用eclipse只需提供JRE(就算提供了JDK,也只有其中的JRE生效)
主要有三处需要配置:
- 是使用eclipse的公有配置,还是使用项目自己的配置。
- 是否选择与java build path中的JRE System Libray的版本一致的内嵌编译器。
- 是否选择eclipse自带的其他版本的内嵌编译器。
然后还需选择Project Facets窗口中的Java版本,须与选择的java compiler版本保持一致:
四、eclipse中的 Installed JREs
可以在该窗口管理eclipse中的所有JRE,不同的项目可以使用不同的JRE,并且勾选上的JRE会作为eclipse的default JRE。
之前在java build path窗口中设置的JRE System Libray就是在这里的Installed JREs当中选的,并且具有两重作用:(对应的,本地JRE文件中有两个主要文件,一者是bin文件,一者是lib文件)
- 设置项目引用的JavaSE jar包的classpath(lib文件在起作用)
- 设置项目会运行在哪个JRE中(bin文件在起作用)
五、将web项目发布到Tomcat
5.1、 Web Deployment Assembly
一般的java项目可以直接运行,但java web项目,则需要放在tomcat中运行。
一般来说,在tomcat的webapps目录下存放各项目文件夹;
在项目文件夹中存放WEB-INF文件夹、资源文件;
在WEB-INF文件夹中存放classes文件夹、jsp文件夹、lib文件夹、xml配置文件;
我们需要将项目的资源文件(如html/css/js、图片等)发布到项目文件夹中;
将自己编写的class文件发布到classes文件夹中;
将自己编写的jsp文件发布到jsp文件夹中;
将引用的第三方jar包发布到lib文件夹中;
如何设置呢?
可以在Web Deployment Assembly窗口配置,这样在项目发布时,会将左侧Source所列的目录中对应的class文件、jar包和资源文件发布到右侧tomcat相应的目录中。
需要注意一点,左侧Source引用的目录存放的是java文件,不过在发布时会只会将其对应的class文件发布到tomcat中。
5.2、Tomcat的JRE
在5.1小节中我曾说过一句话:“一般的java项目可以直接运行,但java web项目,则需要放在tomcat中运行”,所以意味着java web项目要有“发布”这步操作。
但,这还意味着另一件事儿:
我们无论在开发一般的java项目还是java web项目都会在java build path窗口中配置JRE System Libray,进而也就配置了项目的JRE。然而,只有一般java项目会运行在所配置的JRE中,而java web项目由于是运行在tomcat中,所以只会运行在tomcat引用的JRE中。
就可能出现这种情况:我们的java web项目是用java8开发的,也成功发布到tomcat中了,但这个tomcat引用的JRE是java7,导致运行错误。
所以请一定保证开发用的JRE版本与tomcat引用的JRE版本一致。
那如何查看tomcat引用的JRE版本呢:
在命令行窗口中进入tomcat的bin目录,然后键入命令:sh version.sh (linux系统下)即可看到结果:
tomcat引用的是本地操作系统中的环境变量JAVA_HOME或JRE_HOME指向的JRE,所以可以有两种选择:修改tomcat的setclasspath.sh(linux系统下)脚本文件,或修改本地操作系统中的环境变量的值。
5.3、Tomcat需要JDK吗
在tomcat6以前是需要JDK的,在tomcat6及以后的不需要,因为tomcat6及以后也使用了内嵌的编译器Eclipse JDT。那tomcat为什么需要编译器呢?因为需要来编译jsp文件嘛(如果你的项目没有用到jsp,就无需考虑这点)。
六、总结
可见,java虚拟机、java服务器和我们自己写的Servlet构成了整个java web应用的三层结构——java虚拟机屏蔽掉了平台的不一致性,所以tomcat这种java服务器可以运行在任意平台上;java服务器实现了繁杂的HTTP协议,所以我们只需要专注实现基于业务的Servlet;丰富的第三方开源框架和工具让我们实现Servlet更加便捷。这就是一个从底层到顶层完整的java生态圈,也正是java的伟大之所在。
tomcat封装了底层的HTTP协议,但需要提供API给web应用开发者使用。java规定了这些API的接口,tomcat实现了这些API,web应用开发者尽情使用这些API,其乐融融的一家三口(手动滑稽)。
参考链接:
eclipse中新建Java工程的三个JRE选项区别
eclipse配置JDK和设置编译版本的几种方法
注意:eclipse使用自己的编译器
Tomcat是如何将JSP代码编译成Servlet代码的?
Tomcat解惑 之 CATALINA_HOME与CATALINA_BASE
Eclipse配置tomcat会在其下面建立一个Servers工程,请问Servers下面的server.xml和tomcat下面的server.xml有什么区别