Chrisp's blog

NetEase Java Curriculum -- Tomcat&&Maven

Java web

Tomcat

  • 本身tomcat也是java写的,需要java虚拟机,所以tomcat在启动时可以加一些java的参数
  • 通过环境变量JAVA_OPTS可以给加一些启动参数

Tomcat组成与架构

  • 最重要的就是conf下的server.xml文件
    • server 根节点
      • service 可以有多个service
        • connector 用来接受用户请求的,看过就知道他配置了哪个端口处理哪个协议
        • engine 对于一个service只能有一个,他用来处理connector接收到的一些请求的,包括我们平时写的一些代码都是由engine来执行
          • host 在engine里可以有多个host,表示虚拟主机,一般一个ip加一个端口组成一个对。然后我们在请求里加上不同的host头来决定具体路由到哪个host来处理。
            • context 一个context就是一个web应用
  • 一个service就是一个容器(container)
  • tomcat中实现容器(container)的组件是catalina,最终我们的代码都是由catalina里面的代码来执行的
  • 具体到每个参数
    • connector
      • 有个address参数,他指明了这个容器将要监听到IP地址。因为一个服务器将会有多个IP地址,如果不进行配置,他默认将对所有的IP地址进行监听,而这处于安全方面的考量是不被允许的
      • protocol 指名用什么协议,一般开发不会更改,到后面性能调优的时候会有涉及
      • acceptCount 这个参数是用来指明当所有线程都用来处理请求,你的等待队列的长度。有点像理发师那个程序里buffer的长度。
      • maxConnections 最大连接数。需要注意的是他是和你能生成的最大线程数相关的。当你把他的值设为-1的时候表示不限制最大连接数。当然,你虽然设置了-1,但是最大连接数还是要受其他资源的限制。也就是说还是会有最大连接数的
  • 线程池 传统的请求响应方式是你来一个请求,我创建一个线程,建立一个连接,处理这个请求。等请求结束就回收这次的资源。但是这将遇到一个问题就是非常地耗时,因为每次都建立和销毁都是要时间的。所以机智的人类想出来一个方法就是我先提前创建一些线程放在线程池,然后有请求来就响应,响应结束后并不销毁。这就好像医院里面的挂号服务,不管你有没有病人来,挂号窗口都是有服务人员的。
    • 他的配置项是
    • 最小空闲线程数(minSpareThreads) 用来设置线程池最小的线程数。这就好比医院要求的挂号服务在一般情况下最少要有多少个窗口有人值班。
    • 最大线程数 (maxThreads) 用来表示这个线程池能接受的最大线程数。同样类比到挂号服务,就是最多能有多少窗口同时开启工作。之后来的人就得等待。
    • 这两个参数可以直接配置在connector里面,也可以单独的配在Executor里面,然后在connector里面指定依赖关系。
    • 这两个参数构成了另一个概念,弹性线程池。当多于minSpareThreads规定的请求数的时候就会创建其他线程到线程池处理请求,直到创建到最大值。当只有少数请求时,就只开minSpareThreads规定的线程数在线程池。
  • 日志
    • 日志分类
      • 系统运行日志 记录tomcat运行状态,结果等。会捕获一些异常
      • 访问日志 记录所有的请求
      • 应用日志 用户自己写的
    • 配置访问日志 也是在server.xml里面配置
      • 在标签Valve里面配置
      • prefix 指定了你日志命名的开头
      • suffix 指定日志命名的结尾
      • pattern 指名日志里面每一条记录所记录的东西
        • 请求方法是%m ,客户端IP是 %a ,请求时间是 %t ,请求方法是%r ,状态码是%s ,客户端代理是%{User-agent}i
          *fileDateFormat 他常常搭配另一个参数rotatable,当rotatable为true时,fileDateFormat指定了日志以怎样的格式切割。(日志文件切割的意义在于使日志文件不至于过大,这样不至于你检索和查看都会很慢。)如:fileDateFormat: yyyy-MM-dd.时,日志就会每天滚动一次,如果设置成yyyy-MM-dd.HH.那么他每小时就会滚动一次。

Maven

pom.xml

  • groupId 组织名 一般就是用你项目包的前缀命名,如:com.chrisp7
  • artifactId 项目标识符,一般就是写项目名字。不要加点。
  • version 版本 一般都是x.y.z这样的格式。如果你是在开发过程中,那么可以在后面加上一个SNAPSHOT,这样maven会根据这个判断出他是一个在开发的版本。这样maven在你不改版本号的情况下也能判断出哪个新哪个旧。因为她会根据SNAPSHOT自动的打上时间戳。

    groupId artifactId version 是maven中一个项目的坐标,通过这个三个值可以唯一的定位一个项目。这三个的值不能重复。

  • package 类型,如:war

    基本命令

  • mvn archetype:generate 根据模板生成项目
  • mvn compile 编译源代码
  • mvn test 跑测试
  • mvn package 打包
  • mvn 生成项目相关的站点,在线文档
  • mvn install 将包安装到本地仓库,让其他项目进行依赖

    使用maven

  • 使用maven:generate后maven会自动为你生成一些目录,而你的Java文件必须写在src下的java文件中,就像这样This is maven directory
  • mvn archetype:generate 后面要跟很多参数,这些指定了你pom.xml里面的一些东西。其中需要注意的一个参数是DarchetypeArtifactId,如果是webapp,那么这里得是maven-archetype-webapp。如果是一个普通的Java项目,那么就得写成maven-archetype-quickstart
  • 在maven中可以添加一个插件tomcat7,他是集成在maven里面的tomcat。如果你还没用IDE那么这将极大的简化项目的部署。只需要一个指令mvn tomcat7:run即可完成所有。当然,如果你使用IDE这些都可以忽略。
  • 普通的Java项目得有一个resources文件夹在main文件夹下
  • 当用pom来管理多个项目使其形成依赖时,需要在子项目中的pom中指定依赖关系,需要指明groupId,artifactId,version,relativePath.四个标签。同时也需要在最顶层的pom文件中指定有哪些子项目。也就是modules标签。
  • 在pom.xml中,不严肃的说,一个构建就可以等价为一个项目,即project=artifact.
  • 在pom中可以得到这些信息
    • 项目类型(package指定)
    • 坐标
    • 属性(¥{property})
    • 依赖
    • 构建配置(configuration)
    • 多项目,继承
    • 项目总体信息
  • pom继承

    • 可继承项
      • 坐标属性,如groupId.
      • 依赖配置(比如有些子项目都依赖某个配置,就可以把它放到父pom中)
      • 插件配置(公共插件配置)
      • 一般性信息,如开发者信息
    • java中我们都知道所有的类有一个根,就是Object类,那么在pom中是否也有呢?答案是肯定的。就是Super Pom
    • 如果你编辑了pom文件没有显示的定义从哪里继承,那么它就是从super pom继承。可以使用

      1
      mvn help:effective-pom

      查看super pom默认的配置,但是需要注意的的是在这之前你必须保证在同级目录下先创建一个pom文件

    • 超级Pom定义了一组被所有项目能共享的默认设置
      • 默认的文件位置
      • 统一的插件配置
      • 默认的中央仓库的位置
    • 显示的配置
      • 使用parent元素进行配置
  • 依赖配置
    • scope
    • 用于继承的pom配置 dependencyManagement
    • 依赖哪里寻找?仓库 默认仓库目录在~/.m2/repository
    • 远程仓库分类
      • 中央仓库
      • 其他公共仓库(国内使用比较多的开源中国)
      • 私服
    • 配置setting.xml
      实践中遇到一个问题就是当我将所有的pom删掉,重新写一遍依赖关系以后。在本身pom文件没有问题的情况下,他报了个错误could_not_find_artifact.png 我前面由于一知半解,并不知道maven的工作流程。所以一直在想怎么才能把这个Kitchen.jar生成出来。但是之前的做法似乎没有单独生成jar包的说法,毕竟所有的步骤都是maven自动完成的,后来经过网上的查阅,才明白maven的执行是要依赖于库的,有些包可以从网上下载,但是我们自己写的包是需要自己放入本地库的,所以也许之前的某个操作使得我把本地库中的Kitchen.jar删除了,现在必须要把他重新放进本地库。要实现这个操作就要在最顶层的pom文件夹执行mvn install命令。
  • 构建声明周期
    • 每个阶段执行预先定义的动作
    • maven有三个独立的生命周期
      • clean pre-clean post-clean
      • default
      • site 生成一些文档
    • 默认生命周期
      • validate 检查项目的正确性,验证一些必要信息
      • process-resources 将资源文件复制项目中
      • compile
      • test
      • package 编译好的文件打包
      • install 将包安装到本地仓库
      • deploy 将打包好的文件上传远程仓库,这样其他人也可以用
    • 每个阶段怎么做的?
      • 插件式架构
      • 插件本身也是maven中的构建,由maven仓库管理
      • 所有功能由插件提供
      • 插件中有多个目标,每个目标就是一个构建逻辑,你也可以直接指定调用哪个插件的哪个目标来执行。命令:mvn plugin:目标
        • 生命周期与目标绑定
        • 当你在命令行执行某个命令,也就是某个生命阶段的时候实际上就是调用了某个插件目标。
  • 插件
    • mvn内建插件
    • help插件 mvn help:help -Ddetail=true 这个命令告诉你help插件本身的帮助文档、
    • tomcat7 可以把tomcat嵌在maven项目中。不需要另外配置了
    • exec 简单的将jar包跑起来。
  • 插件配置

    • configuration配置 通过命令

      1
      mvn help:describe0 -Dplugin=<plugin_name> -Dgoal=<goal> -Ddetail=true

      可以查看某个插件的某个目标能指定哪些配置项

    • 插件也可以继承,把要公用,也就是继承的插件放到pluginManagement标签就行。

实践中的一些心得

  1. 当你在做服务端开发,需要修改一些配置文件的时候一定要记得备份。可以直接使用如:cp server.xml server.xml.bak命令
  2. 访问网址不一定要用chrome,在终端就可以用curl命令。如:curl http://baidu.com
  3. telnet可以实现发请求发一半,实现占着一个线程的效果
  4. 在linux系统中终端里想看文本内容,可以用cat命令
  5. 解压tar.gz文件使用命令 tar xvzf xxx.tar.gz
  6. 希望在终端打包成一个war包。可以使用命令:jar cvf xxx.war . (别忘了后面有个点,代表当前路径)
  7. 如果希望使用剪切的效果。那就使用mv命令啊,别用cp命令
  8. 可以使用javac -cp apache-tomcat/lib/servlet-api.jar WEB-INF/xxx.java 的方式指定用某个api编译某个Java文件,将其编译为class文件
  9. add external jar jar包没有拷贝进项目 add jar jar包拷贝进了项目