为了方便书写,给出的都是命令行形式,实际上常用命令在各种git客户端里都有对应的操作。
#创建分支
git checkout -b dev origin/dev
#分支切换
git checkout dev
#查看本地分支
git branch
#查看所有分支
git branch -a
#查看分支映射
git branch -vv
#删除分支
git branch -d dev
#清理废弃远程分支映射
git remote prune origin
#合并
#使用客户端操作,命令行解决冲突比较麻烦
#查看变更
git status
#将工作区变更添加进暂存区
git add {
filename}
#将暂存区变更添加到本地分支
git commit -m "commit message"
#将本地分支变更推送到远程分支
git push
#撤销一次commit
git revert {
commit_id}
#撤销一次merge commit
git revert {
commit_id} -m {
parent_no}
查找代码变更位置
场景:想知道一处变更是什么时候改的?谁改的?
操作:以egit为例
选中要查看的文件->右键->Team->Show in History,打开该文件的变更历史。
选中一次commit可以查看变更的文件,双击打开可以查看文件当时的状态,往回追溯即可找到变更位置,时间和提交人都可以查到。
选中commit变更文件列表里的文件右键->Compare with Previous Version 可以查看这次commit中该文件的详细变更情况。
复制提交
场景:想要复制分支中部分commit
操作
1、切换到需要合入的分支
2、找到想要复制的commit
3、命令:git cherry-pick {commit_id}
egit:在git history中选中commit->右键->Cherry-Pick
Build生命周期
生命周期阶段 | 描述 |
---|---|
validate | 检查工程配置是否正确,完成构建过程的所有必要信息是否能够获取到。 |
initialize | 初始化构建状态,例如设置属性。 |
generate-sources | 生成编译阶段需要包含的任何源码文件。 |
process-sources | 处理源代码,例如,过滤任何值(filter any value)。 |
generate-resources | 生成工程包中需要包含的资源文件。 |
process-resources | 拷贝和处理资源文件到目的目录中,为打包阶段做准备。 |
compile | 编译工程源码。 |
process-classes | 处理编译生成的文件,例如 Java Class 字节码的加强和优化。 |
generate-test-sources | 生成编译阶段需要包含的任何测试源代码。 |
process-test-sources | 处理测试源代码,例如,过滤任何值(filter any values)。 |
test-compile | 编译测试源代码到测试目的目录。 |
process-test-classes | 处理测试代码文件编译后生成的文件。 |
test | 使用适当的单元测试框架(例如JUnit)运行测试。 |
prepare-package | 在真正打包之前,为准备打包执行任何必要的操作。 |
package | 获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。 |
pre-integration-test | 在集成测试执行之前,执行所需的操作。例如,设置所需的环境变量。 |
integration-test | 处理和部署必须的工程包到集成测试能够运行的环境中。 |
post-integration-test | 在集成测试被执行后执行必要的操作。例如,清理环境。 |
verify | 运行检查操作来验证工程包是有效的,并满足质量要求。 |
install | 安装工程包到本地仓库中,该仓库可以作为本地其他工程的依赖。 |
deploy | 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程。 |
这几个阶段是从上到下按顺序执行,不同的命令到不同的阶段,但是之前的阶段一定是会执行的。
我们主要关注下面几个命令
compile
编译,生命周期执行到compile为止。
我们可以用它来验证工程是否能正确编译。
test
测试,包含compile,默认执行src/test/java目录下的testcase。
我们目前这一块比较混乱,可以跳过这一步,maven命令中加上参数-Dmaven.test.skip=true
package
打包,包含test、compile,按设置将编译后的代码打包。
可以本地打包验证包是否正常,例如:报名是否符合预期,配置文件是否按逾期打包等
install
发布包到本地仓库,包含test、compile、package,包会被发布到本地maven仓库中。
本地开发时可以将新开发的依赖包发布到本地仓库自己使用。
deploy
发布包到远程仓库,包含test、compile、package、install。
这一步操作有权限限制,通常来说对应的是公司内部部署的maven私服nexus,如果有权限,可以直接将包发布到私服上供其他人使用。
我们目前已经回收了该权限,只保留了服务器上的权限,要发包到私服通过jenkins来实现。
mvn clean
mvn clean可以单独执行,功能是清空target。
也可以叠加执行,例如:mvn clean package,它会先清空target然后再执行package命令,避免旧包干扰。
eclipse插件
无须配置,可直接使用。
#生成eclipse配置文件:.settings、.project、.classpath等
mvn eclipse:eclipse
#清理eclipse配置文件,可以得到比较干净的代码
mvn eclipse:clean
IDEA插件
无须配置,可直接使用。
#生成idea配置文件:.iml、.ipr、.iws等
mvn idea:idea
#清理idea配置文件,可以得到比较干净的代码
mvn idea:clean
dependency插件
无须配置,可直接使用。
#查看工程依赖树
mvn dependency:tree
#导出工程依赖,默认路径:target/dependency
mvn dependency:copy-dependencies
jetty插件
需要在pom.xml中配置插件,如下:
<build>
<plugins>
<plugin>
<groupId>org.eclipse.jettygroupId>
<artifactId>jetty-maven-pluginartifactId>
<version>9.2.8.v20150217version>
<configuration>
<httpConnector>
<port>8080port>
<host>localhosthost>
httpConnector>
<scanIntervalSeconds>1scanIntervalSeconds>
<systemProperties>
<systemProperty>
<name>zk_groupname>
<value>sitvalue>
systemProperty>
systemProperties>
<webApp>
<contextPath>/cbms-webcontextPath>
webApp>
configuration>
plugin>
plugins>
build>
#无须外部容器即可启动web程序,支持热部署
mvn jetty:run
2.2中的dependency插件可以查看,但是不够详细。
我们日常使用时可以使用客户端来查看,方便使用且功能更强大。
以eclipse为例:
打开pom.xml,选择下方的页签Dependency Hierarchy
,可以看到详细依赖树,在右上角还有筛选功能,最重要的是它标注了版本号的覆盖情况,方便分析问题。
如图,我筛选出了slf4j-api,专注分析整个依赖,从左边的依赖树可以看到,这个依赖有4处依赖,其中log4j-over-slf4j-1.7.7依赖了slf4j-api-1.7.7、logback-classic-1.1.2依赖了slf4j-api-1.7.6,因为ares-parent中依赖了slf4j-api-1.7.2,这个依赖层级最高,将log4j-over-slf4j-1.7.7和logback-classic-1.1.2的依赖强制改为了slf4j-api-1.7.2。
补充说明:我们现在的工程结构使用了Maven CI Friendly Versions结构,发布时通过flatten-maven-plugin插件
简化了pom.xml,所以本地代码中的pom.xml依赖不准确,最终依赖以仓库中的pom.xml为准,如果需要可以将仓库中的pom.xml拷贝出来分析。
在maven仓库中,包名以-SNAPSHOT结尾的包是快照包,会特殊处理。
找到快照包在仓库中的目录,会发现有很多包名中带时间戳的包,这就是快照包的特殊之处,它的一个版本号里会有很多包,代表该版本号的包是时间戳最新的包。这种设计是为了可以覆盖旧包,主要用于内部开发阶段,代码非常不稳定,但是又需要给出来用。
PS:因为快照包会一直覆盖旧包,那么就肯定会出现本地包不是最新的情况,毕竟你的包名没变,本地maven除非每次都去服务器上查一次,不然是不能保证本地包最新的。如果需要拿到最新的快照包,可以在maven命令中加上-U,强制要求更新。
既然特殊处理的快照包设计成可以覆盖旧包,那么对应的其他版本包应该就是不能覆盖的了?确实是这么设计的,如果不能理解这点在日常使用中会有很大的困惑。
我们设想一个场景,spring官方发布了1.0.0版本—spring-1.0.0,我们用了这个包,使用了里面的ClassPathXmlApplicationContext类;
然后spring官方又觉的ClassPathXmlApplicationContext这个类设计的不好,给干掉了,然后他们觉的改动不大,偷懒没有升级版本号,用新代码发布了新的spring-1.0.0。这个时候我们就麻烦了,有的同事按要求去下载到新的spring-1.0.0后发现没有ClassPathXmlApplicationContext,代码没法使用,用旧包的人没问题,明明都是1.0.0的包。
为了避免这种情况,maven设计上给你留了可以覆盖的快照包开发用,其他的非快照包是不能覆盖的,你给出去让别人用的包不能乱改,只能升级版本号发布新包。具体的限制是本地仓库不会更新非快照包,即使你手动去私服上把这个包干掉重新上传一个;私服默认也不能deploy已经有的非快照包。
@Value("#{env['redis_expire_time']?:3600}")
private int redisExpireTime;
<property name="driverClassName" value="#{env['jdbcDriver']}"/>
我们系统中大部分参数都是通过上面这种形式来取参数,这种形式的参数来源其实比较复杂,不熟悉的话,往往都不太清楚具体一项参数是从哪里来的。
我们来了解下参数都是从哪里来的:
先从env参数开始
<bean id="env" class="com.allinfinance.ares.facility.config.AresEnvironmentFactoryBean">
<property name="locations" value="#{systemProperties['env.files'] ?: 'classpath:/conf/*.properties'}" />
bean>
这是我们使用的参数的起点,可以看到,这里是在设置配置文件路径,默认从环境变量里取env.files的值,如果没有就取conf目录下的所有properties文件。我们目前没发现有配置env.files,这里直接当做取conf目录下properties文件。
PS:systemProperties在AbstractApplicationContext.prepareBeanFactory方法中注册的。
接着进AresEnvironmentFactoryBean类看看
public class AresEnvironmentFactoryBean extends PropertiesLoaderSupport
implements FactoryBean<Properties> {
private Logger logger = LoggerFactory.getLogger(AresEnvironmentFactoryBean.class);
@Override
public Properties getObject() throws Exception {
Properties props = new Properties();
Map<String, String> env = System.getenv();
// 从配置的本地文件取值
super.loadProperties(props);
// 环境变量定义的优先
if (StringUtils.isNotEmpty(env.get("instanceName"))) {
logger.info("发现instanceName环境变量,开始从环境变量取值.");
props.putAll(System.getenv());
}
// 命令行上的参数优先级最高
props.putAll(System.getProperties());
String dpf = props.getProperty("decryptFieldName");
if (dpf != null && dpf.trim().length() > 0) {
String decryptFieldName[] = dpf.trim().split(",");
for (int i = 0; i < decryptFieldName.length; i++) {
String s1 = props.getProperty(decryptFieldName[i]);
String s2 = ThreeDes.decryptMode(decryptFieldName[i], s1);
props.setProperty(decryptFieldName[i], s2);
}
}
return props;
}
@Override
public Class<?> getObjectType() {
return Properties.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
这是一个FactoryBean的实现,从getObjectType方法看最后产生的是一个Properties类,生成过程在getObject中,首先调用了PropertiesLoaderSupport的loadProperties方法,这是spring的类,会处理之前配置的通配符并加载这批配置文件到props对象中。
然后判断系统环境变量里是否有instanceName这个配置,如果有,就将环境变量里的配置覆盖进props对象中。
接下来是将命令行参数覆盖进props对象中。再后面是处理一些3DES加密过的参数。处理完成后将props对象输出。
从这段逻辑可以看出,我们系统中类似#{env['zk_group']}
这种从env对象中获取参数的形式遵循一套规则,参数来源有4个途径:配置路径的配置文件中读取的参数、系统环境变量、虚拟机启动参数、加密参数,他们的优先级规则是:加密参数>虚拟机启动参数>系统环境变量>配置路径的配置文件中读取的参数。
知道这个规则后,去找参数就简单了,按图索骥:
配置路径的配置文件中读取的参数
这部分配置通常都是读工程内部conf目录下的properties文件,直接去工程里找即可。
系统环境变量
我们的服务器操作系统使用的是CentOS,我们都知道添加环境变量有三种方法:
去这几个地方检察下,发现这部分参数有两个来源:
.bash_profile->.bashrc->~/apphome/lkl.env
~/apphome/bin目录下的启动脚本,这里边主要引入了common.env和一个私有env,一种比较便捷的查询方式是进入conf目录搜索所有的env文件,例如要查消息队列的配置
cd ~/apphome/conf
cat *.env|grep queue
PS:如果想要查看当前生效的系统环境变量可以通过命令查看
#linux系统查看当前生效环境变量:echo ${key}
echo $JAVA_HOME
#window系统查当前生效环境变量:echo %{key}%
echo %JAVA_HOME%
虚拟机启动参数
这部分可以通过启动脚本查到来源,通常来说它会混合环境变量、脚本配置来组装启动命令。
一种比较便捷的查询方式是直接查进程看启动脚本,例如:ps -ef|grep banknf-web,因为我们是通过jsvc来启动服务,它会启动一个守护进程,通过这个命令查看时会发现有两个进程,注意看两个进程的PPID,PPID是1的是守护进程,PPID是守护进程PID的进程即是虚拟机进程。
加密参数
没发现有这个参数的使用,一般忽略它。
因为我们的服务大多基于dubbo,dubbo的服务发现基于zookeeper,当服务异常时,检查下zookeeper里的数据节点有助于排查问题。
zookeeper官方提供了客户端访问工具zkCli,下载zookeeper包,解压后将其内部的bin目录配入环境变量接口在cmd环境使用zkCli命令。
#连接zookeeper服务
zkCli -server 192.168.0.150:2181,192.168.0.151:2181,192.168.0.152:2181
zk服务正常的话,会出现一个命令行环境。
按dubbo服务发布规则查看注册上来的服务(/{group}/{interface})
#查询sit环境adm的服务GenerateSequenceService发布情况
ls /sit/com.allinfinance.adm.service.api.GenerateSequenceService/providers
如果得到的是空的,说明没有活跃服务,adm服务应该是挂了,去检查该服务。
如果得到一个有值的数组,这就是dubbo服务发布方信息,因为做了unicode加密,里面有很多奇怪的%之类的符号,这些都是标点符号之类的符号转换的,其他的信息可以正常阅读,如果觉的碍眼可以找一个unicode加解密工具还原,这种工具有很多在线版。
使用完毕后,输入quit退出。
与zkCli类似,Redis也提供了自己的客户端工具redis-cli,配入环境变量即可在cmd环境使用。
#连接redis
redis-cli -h 192.168.0.150 -p 6384 -c
#查键(例如查sit环境所有键),这个命令会影响redis运行,不要在生产环境使用,如果要在生产环境查询请使用scan命令
keys sit:*
#查键值,如果没有该键返回(nil)
get sit:dcn_mode:135
#删除键
del {
key}
#查看键存活时间(-1表示未设置存活时间,-2表示已失效)
ttl {
key}
实际用途:
查adm映射
我们adm缓存映射key组成规则:{namespace}:{keyType}:{keyValue}
举例:查sit环境借据号0120320810000077041对应的cust值,get sit:D:0120320810000077041
一种比较常见异常:分区错误,查看日志发现分区要素keyValue没有传值,把keyValue设置成null查下,应该是查到错误的custId了。
查服务开关
我们的服务开关判断依据是redis中的key值,当BMP中配置不符合预期时,可以去redis中查询对应开关的key值验证问题。
服务控制key规则:{namespace}:{org}:{服务编号}:{渠道号}
举例:sit环境000000000001机构预授权(APP)拉卡拉钱包APP的key是sit:000000000001:04B101:01
当服务控制key值是Y
时表示服务开通
提示:当渠道服务key值表示关闭时不一定服务不可用,还要检查下该服务开通全部渠道(渠道号为00)的情况
Eclipse Explorer
快捷跳转工具,在Explorer窗口选择想要跳转的目录->右键->Open in Explorer,即可直接到达文件位置。
提示:依赖也可以跳转,会直接跳到本地仓库该包的位置