0%

mybatis学习笔记。

0x00 阅读源代码

下载源代码

  • 代码仓库地址 https://github.com/mybatis/mybatis-3.git
  • 阅读版本号 myabtis-3.5.0
  • 下载版本git clone -b mybatis-3.5.0 https://github.com/mybatis/mybatis-3.git
    • 由于github下载速度是在太慢了,这里用gitee克隆一个镜像。
    • 下载版本git clone -b mybatis-3.5.0 https://gitee.com/Z201/mybatis-3.git

查看源代码结构

  • 查看项目主要文件夹
1
2
3
4
5
6
7
tree -d L 2
.
├── src
│   ├── main # 源代码
│   ├── site # 站点稳当
│   └── test # 单元测试
└── travis # 官方的ci集成
  • 查看项目源码主目录
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
tree -d src/main -L 5
src/main
└── java
└── org
└── apache
└── ibatis
├── annotations # 注解
├── binding # 代理
├── builder # 构造
├── cache # 缓存
├── cursor # 返回值类型为游标的方法
├── datasource # 数据源
├── exceptions # 异常
├── executor # 数据操作具体执行
├── io # 文件流
├── jdbc # jdbc模块
├── lang # 工具
├── logging # 日志
├── mapping # 映射、参数、结果集。
├── parsing # 解析器
├── plugin # 插件
├── reflection # 反射
├── scripting # sql解析
├── session # 接口层会话
├── transaction # 事物
└── type # 类型
  • 将项目导入idea中,就可以看到完整的源代码了。

0x01 根据官方文档快速入门

强烈推荐认真阅读mybatis的官方文档。

本章是整理知识内容,为强化知识长期更新。

Git速度查询表

下面是常用 的Git 命令清单。几个专用名词的译名如下:

  • Workspace:工作区
  • Index / Stage:暂存区
  • Repository:仓库区(或本地仓库)
  • Remote:远程仓库

最小配置

为什么要最小配置,每次提交代码需要告诉git。所以需要简单设置下user信息。

1
2
git config --global user.name 'your name'
git config --global user.email 'your email'

这里需要注意config的三个作用域

1
2
3
git config --local  #某个git本地仓库有效
git config --global #当前用户所有仓库有效,就是你系统的登陆用户。
git config --system #对系统所有的仓库都有效果。

我们一般只会使用local 和 global这两个配置。当我们配置好user.name user.email之后,我们可以检查下配置信息。

1
2
3
git config --list --local # 注意,必须在某个仓库里面才能看到。
git config --list --global
git config --list --system

创建一个本地仓库

一般来说git仓库有两种情况,一种是没有仓库,另外一种就是已经有仓库了。这里对第一种情况演示,因为工作中习惯在web上创建仓库。这里还是了解下。

1
git init git_learning 

创建一个README文件。

1
touch README.md

这里需要说明下,本地仓库创建完成后需要与远程仓库进行管理。

1
git remote add origin github.com:yourname/git_learning.git # 这里的yourname 是你的git账号

建议手动去github上面创建一个叫git_learning的仓库。上面的命令就是做下关联。

1
2
3
git add . # 将当前文件添加至暂存区
git commit -m "upload file" # 将暂存区的文件提交到本地仓库
git push origin mastet # 将本地仓库的改动信息推送到远程仓库中

可控一个远程仓库

1
2
# 克隆一个仓库
git clone www.**/**.git

文件追踪

有些时候不想提交部分文件,但是git add .的时候添加进去了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## 添加文件到暂存区
git add [file] [file]

## 添加文件夹暂存区
git add [dir]

## 添加当前目录所有文件暂存区
git add .

## 如果是对所有文件都取消跟踪的话,就是
git rm -r --cached .    ## 不删除本地文件
git rm -r --f .    ## 删除本地文件

##对某个文件取消跟踪
git rm --cached readme1.txt ## 删除readme1.txt的跟踪,并保留在本地。
git rm --f readme1.txt ## 删除readme1.txt的跟踪,并且删除本地文件s

提交仓库

如果发现message写错了,可以修改下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 修改最新一次commit提交message。
git commit --amend

# 提交暂存区的指定文件到仓库区
git commit [file1] [file2] ... -m [message]

# 将本地暂存区的文件推送到本地仓库。 当修改已经通过`git add <change file>`将其添加到`stage`,可以通过`git commit -m "<message>"`为这所有已经进入`stage`的改变添加一个`commit`信息。
git commit -m

#可以直接使用`git commit -am "<message>"`,将所有修改,但未进`stage`的改动加入`stage`,并记录`commit`信息。(某种程度上相当于`git add`和`git commit -m`的组合技,前提是被改动文件已经是`tracked`)
git commit -am

#这个命令经常会出现在本地仓库与远程仓库发生冲突的时候,需要强制推送更新。
git push -f origin master

# 推送删除远程分支操作
git push origin : xxxx

# 推送删除远程分支操作
git push origin --delete xxxx

  • 如果想修改以往的commit的message。注意是不连续的commit。
    • 首先查看log 里面的信息,然后获取commitid进行合并
阅读全文 »

本章是整理知识内容,为强化知识长期更新。

Dubbo概述

  • 服务治理(SOA)治理框架
  • Duboo是一个分布式服务框架
    • 远程通讯:提供多种基于长链接的NIO框架抽象封装,包括多种线程模型、序列化“请求-响应”的信息交换方案。
    • 集群容错:提供基于接口方法的透明远程调用过程,包括多协议支持、软负载均衡、失败容错、地址路由、动态配置等集群支持。
    • 自动发现:基于注册中心目录服务,使服务消费方能动态地查找提供方,使地址透明,使服务提供方可以平滑增或减少机器。
    • 介绍:
    • 致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
    • Dubbo的命名:澳大利亚达博市
    • 同类型框架:
      • Apache Thrift、Hessian、RMI、WebService(原生)、HSF(淘宝,不开源)、JSF(京东,不开源)。
    • Dubbo涉及的基础知识
      • 远程调用方面:RMI、Hassion、WebService、Thrift进行底层调用。
      • 通讯交互:HTTP、Mian、netty。
      • 序列化:Hession2、Java、Json。
      • 容器:Jetty、Spring。
      • 负载均衡:zookeeper、Redis。(大部分都是zookeeper)
    • 简单的使用场景
      • 作为对内提供服务应用的容器。
      • 拆分负载Web应用到服务容器。
      • 应用负载均和协调。
      • 引用服务处理。

架构节点(抽象概念)

  • Provider:暴露服务的服务提供方。
  • Consumer:调用远程服务的服务消费方。
  • Registry:服务注册于发现服务
  • Monitor:统计服务的调用次调用时间监控中心
  • Container:服务运行容器
    • 节点调用关系
    • 服务提供-服务提供者在启动的时候,向注册中心提供自己提供的服务。
    • 服务消费-服务消费者在启动的时候,向注册中心订阅自己所需要的服务。
      • 注册中心异步返回服务提供者地址列表给消费者,如果有变动,注册中心将给予长连接推送变更数据给消费者。
    • 服务统计-服务者和消费者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
      • 异步方式
    • 服务调用关系
      • 服务消费者,从提供者地址列表中,基于[软负载均衡算法],选一台提供者进行调用,如果调用失败,在选另一台调用。

Dubbo源码相关

  • 源码地址git clone https://github.com/alibaba/dubbo

  • 初次编码不执行Test mvn clean install -Dmaven.test.skip=true

  • JS错误不修改,请自行忽视。

  • 修复mavan的警告
    * 地址:dubbo-parent pom.xml
    * maven-jar-plugin version:2.4
    * maven-surefire-plugin Version 2.19.1
    * maven-deploy-plugin Version 3.3.9

  • 项目导入后修复Dubbo XML校验错误提示

  • 需要导入dubbo.xsd文件

  • 下载dubbo-2.5.3.jar 版本尽量保持源码同步,解压dt后导入eclipse中。

    • Preferences-XML-XML Catalog 添加一个自定义的:

      1
      <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dubbo SYSTEM"http://code.alibabatech.com/schema/dubbo">
  • 关于maven-dependency-plugin错误 可能是IDE错误提示,空白处添加空格保存自动消失。

    • 错误信息如下:Artifact has not been packaged yet. When used on reactor artifact, unpack should be executed after packaging: see MDEP-98. (org.apache.maven.plugins:maven-dependency-plugin:2.8:unpack:unpack:package)

      • 修复方案更改插件配置:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      <?xml version="1.0" encoding="utf-8"?>

      <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <version>2.10</version>
      <executions>
      <execution>
      <id>unpack</id>
      <phase>packaged</phase>
      <goals>
      <goal>unpack</goal>
      </goals>
      </execution>
      </executions>
      </plugin>
  • Dubbo源码模块

    • Config配置层(Dubbo-config)
    • Proxy服务代理层(Dubbo-rpc)
    • Registry注册中心层(Dubbo-registry)
    • Cluster路由层(Dubbo-cluster)
    • Monitor监控层(Dubbo-monitor)
    • Protocol远程调用层(Dubbo-rpc)
    • Exchange信息交换层(Dubbo-remoting)
    • Transport网络传输层(Dubbo-remoting)
    • Serialize数据序列化层(Dubbo-common)

Zookeeper

(测试方案采用zookeeper做均衡负载,简单介绍下配置信息)

  • 下载地址 http://apache.fayea.com/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gz
  • 基本配置:
    • 单机模式:修改zookeeper-3.4.8/conf zoo.cfg(原始文件名zoo_sanple.cfg复制一份重命名)
      • 编辑内容(仅供参考,具体环境自行修改)
      • tickTime = 2000
        • tickTime:基本事件单元,以毫秒为单位。这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。
      • initLimit= 5
        • initLimit:这个配置项用来配置Zookeeper接受客户端初始化连接时最长能忍受多少个心跳时间间隔数,当已超过5个心跳的时间(也就是tickTime)长度后Zookeeper服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度是5 * 2000=4s。
      • dataDir = D:\zookeeper\data
        • 顾名思义就是 Zookeeper 保存数据快照的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里)。
      • dataLogDir= D:\zookeeper\log
        • 顾名思义就是 Zookeeper 保存日志的目录。
      • synclimit = 5
        • 这个配置项表示Leader与Follower之间发送消息,请求和应答时间长长度,最长不能超过多少个tickTime的时间长度,总的时间长度是2 * 2000 = 4s。
      • clientPort = 2181
        • 这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
      • Server(待续)
        • 格式:server.id=host:port:port(两个port保证可以正常使用就行)
          • id:通常为整数,建议使用整数。
          • host:服务器的IP地址。
          • port: Follower端口
          • port: Leader选举投票。
        • ZooKeeper建议使用hostname,而非ip。这需要对主机的/etc/hostname和/etc/hosts做host绑定(不用的OS不同修改方式)。
      • 创建一个myid文件(放在 dataDir文件下面)
        • 写入一行数据(请查阅zoo.cfg文件)
          • 写入当前Zookeeper id位置的数据即可。表示当前系统环境Zookeeper是哪一个Server(通讯用的)。

Dubbo程序运行

  • 测试运行,默认配置即可。注意与zookeeper一台机器。
  • 运行Dubbo-admin本机tomcat启动启动成功后127.0.0.1:8080/dubbo-admin(注意默认请设置跟目录,否则部分功能不发正常显示)
    • 默认用户名密码(root/root,guest/guest)

本章是整理知识内容,为强化知识长期更新。

面向对象思想

  • 面向对象是一个思想,时间万物皆可以被看做一个对象。

封装

  • 隐藏对象的属性和实现的具体细节,只对外暴露公共访问方式。

继承

  • 当多个类出现相同代码逻辑时,我们通常将相同的代码重构到一个类中,如果是绑定关系就可以使用继承。
  • Java中类是单继承。多继承会导致棱形问题。
  • 继承是面向对象的四大特性之一,用来表示类之间的 is-a 关系,可以解决代码复用的问题。虽然继承有诸多作用,但继承层次过深、过复杂,也会影响到代码的可维护性。
    • 可以利用组合(composition)、接口、委托(delegation)三个技术手段,一块儿来解决刚刚继承存在的问题。

多态

  • 一个事物的的多种状态,比如女人、男人都是人的性别。人的性别就分为女人、男人。

抽象

  • 在逻辑上看似相关的,想要把他们联系起来。这样可以提高效率。矩形、圆形,都可以具有周长和面积两个方法,但是计算的方式完全不同,矩形和圆形之间肯定不能构成子父类的关系,那么只能是同时去继承一个父类。这时,就引出了抽象的概念。

总结

  • 封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或者数据。它需要编程语言提供权限访问控制语法来支持,例如 Java 中的 private、protected、public 关键字。封装特性存在的意义,一方面是保护数据不被随意修改,提高代码的可维护性;另一方面是仅暴露有限的必要接口,提高类的易用性。
  • 抽象可以通过接口类或者抽象类来实现,但也并不需要特殊的语法机制来支持。抽象存在的意义,一方面是提高代码的可扩展性、维护性,修改实现不需要改变定义,减少代码的改动范围;另一方面,它也是处理复杂系统的有效手段,能有效地过滤掉不必要关注的信息。
  • 继承是用来表示类之间的 is-a 关系,主要是用来解决代码复用的问题。
  • 多态是指子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现。多态这种特性也需要编程语言提供特殊的语法机制来实现。主要解决扩展性问题。

接口与抽象类

如果我们要表示一种 is-a 的关系,并且是为了解决代码复用的问题,我们就用抽象类;如果我们要表示一种 has-a 关系,并且是为了解决抽象而非代码复用的问题,那我们就可以使用接口。

  • 接口:它是一种自上而下的设计思路。我们在编程的时候,一般都是先设计接口,再去考虑具体的实现。

    • 实际开发过程中,容易过度使用比如给每个类都定义接口。
    • 基于接口而非实现编程”这条原则的英文描述是:“Program to an interface, not an implementation”
    • 从本质上来看,“接口”就是一组“协议”或者“约定”,是功能提供者提供给使用者的一个“功能列表”。“接口”在不同的应用场景下会有不同的解读,比如服务端与客户端之间的“接口”,类库提供的“接口”,甚至是一组通信的协议都可以叫作“接口”。
  • 抽象类 :抽象类是一种自下而上的设计思路,先有子类的代码重复,然后再抽象成上层的父类(也就是抽象类)

    • 抽象类不允许被实例化,只能被继承。它可以包含属性和方法。方法既可以包含代码实现,也可以不包含代码实现。不包含代码实现的方法叫作抽象方法。子类继承抽象类,必须实现抽象类中的所有抽象方法。接口不能包含属性,只能声明方法,方法不能包含代码实现。类实现接口的时候,必须实现接口中声明的所有方法。

    • 每个优秀的程序员都知道,不应该定义一个attackBaghdad() ‘袭击巴格达‘ 的方法,而是应该把城市作为函数的参数 attack(city)。

重写和重载

  • 重载:同一个类中,方法名相同,参数个数或者类型不相同,返回类型可以不相同。
  • 重写:类的继承关系中体现,子类重写父类的方法。
区别点 重载方法 重写方法
发生范围 同一个类 子类
参数列表 必须修改 一定不能修改
返回类型 可修改 子类方法返回值类型应比父类方法返回值类型更小或相等
异常 可修改 子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;
访问修饰符 可修改 一定不能做更严格的限制(可以降低限制)
发生阶段 编译期 运行期
  • 重写(override)

    • 存在父类和子类之间。
    • 方法名、参数、返回值相同。
    • 方法被final修饰不能被重写。
    • 子类重写父类方法后,不能抛出比父类方法的异常。子类不能缩写父类的方法访问权限
  • 重载(overload)

    • 参数类型、个数、顺序至少有一个不相同。
    • 不能重载只有返回值不同的方法名。
    • 存在于父类和子类、同类中。
  • Constructor 不能被 override(重写),但是可以 overload(重载),所以你可以看到⼀个类中有多个构造函数的情况。

介绍下 Java 基本数据类型

  • Java中存在8个原生数据类型,同时又分成四种:整形、浮点型、char、Boolean。它们之间存在自动类型转换,规则是从小到大。并且都存在自动装箱拆箱特性,但是这种操作是隐式操作而且在某些情况会导致CG压力增大。
类型 存储需求 取值范围
int 4字节 -2 147 483 638 ~ 2 147 483 637
short 2字节 -32 768 ~ 32 767
long 8字节 -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807
byte 1字节 - 128 ~ 127
  • 整型的范围与运行Java运行的硬件没有关系,所有的数据类型所占的字节数量与平台无关。
类型 存储需求 取值范围
float 4字节 大约 $\pm$ 3.402 823 37F + 38F (有效位数为7~8位)
double 8字节 大约 $\pm$ 1.797 693 134 862 315 70E + 308 (有效位数为15位)
  • double这种类型的精度是float的两倍。

  • 所有浮点数值计算都遵循IEEE 754规范,下面是溢出和出错的情况的三种特殊的浮点数值。

    • 正无穷大
    • 负无穷大
    • NaN ( 不是一个数字 )
    • 一个整整数除以0的结果为正无穷大,计算0/0或者负数的平方根结果为NaN。
  • char类型

    • char类型表示单个字符,属于Unicode编码表。因为历史原因,不建议在程序中使用。除非确实要对UTF-16代码单元进行操作。
    • char字节大小
      • Java中无论是汉字还是英文字母都是用Unicode编码来表示的,一个Unicode是16位,每字节是8位,所以一个Unicode码占两字节。但是英文字母比较特殊,源自于8位(1字节)的ASCII吗,于是在Unicode码仅使用了低8位(1字节)就可以表示。
  • boolean类型

    • 布尔类型,只有两个值false、true。基本用于判定条件。
    • boolean字节大小
      • Java规范中并未明确规定boolean类型的大小。
  • 自动类型转换

    • 整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。

      转换从低级到高级。

      1
      byte,short,char—> int —> long—> float —> double 
    • 不能对boolean进行类型转换、不能把对象类型转换成不相关的对象、把大容量的对象转换成小容量对象时需要强制类型转换、转换过程中间可能出现精度损失。

装箱和拆箱boxing or unboxing

装箱:将基础类型用它们对应类型包装起来

拆箱:将包装类型转换成基本数据类型

原语 对应的JDK类
int java.lang.Integer
short java.lang.Short
long java.lang.Long
byte java.lang.Byte
char java.lang.Character
double java.lang.Double
float java.lang.Float
boolean java.lang.Boolean
  • Java中只有原生数据类型是特殊的,它们不是对象。其它的都是对象。那么就一个尴尬的问题,集合类都是存放的对象,JDK5之后考虑到这个问题就自动进行逆行拆箱装箱的操作。

    1
    2
    3
    //比如所在泛型中是不能存放原生数据类型的,如要要存放原生数据类型的数据,需要装箱。
    Collection<int> c = new ArrayList<int>(); //这是无法编译成功的。
    Collection<Integer> cc = new ArrayList<Integer>(); //这样才行。
  • 每个 JDK 类都提供了相应方法来解析它的内部表示,并将其转换为相应的原语类型。

  • 但是注意装箱拆箱操作其实是非常消耗内存的举动,在该过程中可能会生成生成无用对象增加GC压力。所以尽量避免这中操作。

    1
    2
    3
    4
    Integer sum = 0;
    for(int index = 1000; index < 5000; index ++){
    sum+=index;
    }

    比如这种,每次sum都需要自动拆箱。

  • 默认情况下整数的类型都是int、浮点型的数都是double。

    1
    float d = 1.1f; //在后面添加f,大小写不区分。隐式强制类型转换
阅读全文 »

本章是整理知识内容,为强化知识长期更新。

Java集合

​ 集合是Java提供的工具包、包含常用的数据结构:集合、链表、队列、栈、数组、映射等。Collection的包是java.util.*。

Collection

Map

实际上还有Cloneable、Serializable接口是都集合类需要实现的,通用所以不不画上去了。

Java集合主要划分4个部分:

  • List(列队)
  • Set(集合)
  • Map(映射)
  • 工具类(Iterator迭代器、Enumeration枚举类、Arrays、Collections)

划重点

  • Conllection
    • List
      • ArrayList
      • Vector
        • Stack
      • LinkedList
    • Set
      • HashSet
      • TreeSet
      • LinkedHashSet
    • Queue
  • Map
    • HashMap
    • HashTable
    • TreeMap
  • 工具
    • Arrays
    • Collections
    • Enumeration

Java类库中具体集合

集合类型 概括
ArrayList 一种可以动态增长和缩减的索引序列,访问速度很快但是插入和删除比ArrayList慢。
LinkedList 一种可以在任何位置进行高效地插入和删除操作的有序序列,但是访问比较ArrayList慢。
CopyOnWriteArrayList CopyOnWriteArrayList相当于线程安全的ArrayList,它实现了List接口,支持高并发。
ArrayDeque 一种循环数组实现的双端序列。
HashSet 一种没有重复元素的无序集合。
TreeSet 一种有序集合。
EnumSet<E extends Enum> 一种包含枚举类型的集合。
LinkedHashSet 一种可以记住元素插入顺序的集合。
PriorityQueue 一种允许高效删除最小元素的集合。
HashMap<K , V> 一个存储 键 / 值 关联的数据结构。
TreeMap<K , V> 一种键值有序排列的映射表。
EnumMap<K extends Enum, V> 一种键属于枚举类型的映射表。
LinkedHashMap<K ,V > 一种可以记住键 / 值 项添加顺序的映射表。
WeakHashMap<K , V > 一种其值无用武之地后可以被垃圾回收回收的映射表。
IdentityHashMap<K , V> 一种用 == 而不是用用 equals 比较的映射表。
阅读全文 »

本章是整理知识内容,为强化知识长期更新。

Mavan常用命令以及用法

  • 常用命令就要先了解Maven的生命周期
    • Maven的生命周期就是对所有的构建过程进行抽象和统一。包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。
    • Maven的生命周期是抽象的,即生命周期不做任何实际的工作,实际任务由插件完成,类似于设计模式中的模板方法。所以必须有对应的插件才能执行对于的步骤。
    • Maven有三套相互独立的生命周期,分别是clean、default和site。每个生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。
      • clean生命周期:清理项目,包含三个phase。
        • 1.)pre-clean:执行清理前需要完成的工作。
        • 2)clean:清理上一次构建生成的文件。
        • 3)post-clean:执行清理后需要完成的工作。
      • default生命周期:构建项目,重要的phase如下。
        • 1)validate:验证工程是否正确,所有需要的资源是否可用。
        • 2)compile:编译项目的源代码。
        • 3)test:使用合适的单元测试框架来测试已编译的源代码。这些测试不需要已打包和布署。
        • 4)Package:把已编译的代码打包成可发布的格式,比如jar。
        • 5)integration-test:如有需要,将包处理和发布到一个能够进行集成测试的环境。
        • 6)verify:运行所有检查,验证包是否有效且达到质量标准。
        • 7)install:把包安装到maven本地仓库,可以被其他工程作为依赖来使用。
        • 8)Deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。
      • site生命周期:建立和发布项目站点,phase如下。
        • 1)pre-site:生成项目站点之前需要完成的工作。
        • 2)site:生成项目站点文档。
        • 3)post-site:生成项目站点之后需要完成的工作。
        • 4)site-deploy:将项目站点发布到服务器
阅读全文 »