maven相关
包下载
maven项目永远是去本地仓库找JAR包,本地没有的,也是从远程仓库(一级一级找,最后到中央仓库)下载到本地仓库,然后再从本地仓库里面拷出到项目里面。
maven有自己的一个默认中央仓库,在setting.xml里面是看不到的,它的ID是central。
maven的下载机制,是在repository里面,一个仓库的去找你要的东西。而镜像的作用是屏蔽指定的repository并用镜像替代,并不影响其本身的下载机制。
所以镜像的mirrorOf不要选*,这样你就相当于屏蔽了所有的仓库,这是不合适的,mirrorOf最好就填写central,这样就兜底了中央仓库。
类加载
java本身是不会报类冲突的,是因为java类加载的机制,是从类目录下一个个的找(不仅包括引用的jar包,还包括本身的class程序文件),找到了就停下来。
会报冲突的是maven或者编译器的功能。Maven其实很智能,如果是两个一样artifact和groupid的话,不同版本的,在下载的时候都会下载下来,但是编译的时候,只会保留高版本。(maven应该会提示?不然直接就覆盖了,不兼容怎么办)
打出可执行的jar包
正常打jar包的话,被引入的三方jar包是不会一起被打入jar包的,只会有pom跟着你。所以的话,如果你这个jar包被别人用,那个人没用maven的话,是跑不起来的。
要想jar包一打就能用,也就是把三方jar也加到jar包里面(一般我们下载的第三方开源jar不会采用这种方式,因为这样会导致jar包冗余),有两种方式:
- 通过export打jar包的时候要选择runablejar,里面可以配置你是要把第三方jar配置在本jar包的面,还是外面。这样的话,它会在MANIFEST.MF里面,把你的第三方jar的地址放进去。一个接着一个jar就能衔接上了。
- 先设置project sturcture里面的artifact,把三方jar加入依赖,然后再通过build里面的artifact build打包。(这里有一点需要注意,manifest的位置不能放默认位置,需要放到resource下,不然IDEA12有bug,识别不了manifest文件)
依赖树
maven里面查看依赖树,用mvn dependency:tree,如果要看详细的,再加参数-Dverbose,如果是要包括或者删除哪些,再用-Dincludes=xx:xx:xx -Dexcludes=xx:xx:xx。
mvn dependency:tree -Dverbose -Dincludes=xx:xx:xx -Dexcludes=xx:xx:xx
生命周期
maven一共有三个生命周期,分别是clean,validate–>compile–>test–>package–>verify–>install,site。
在同一个生命周期内,当你执行一个构建阶段时,所有在该构建阶段之前的构建阶段(根据标准构建顺序)都会被执行。
仓库路径
maven有个巨坑,在配置本地仓库路径的时候,默认是/root/.m2/repository,我也没有去改。
但是在下载和使用jar包时,它使用了C盘下的/root/.m2/repository(猜测是因为maven安装在C盘),但是在install上传jar包时,却使用的是D盘下的/root/.m2/repository(猜测是因为项目源码是在D盘)。。。。
最后在setting的配置文件中手动把仓库路径改成C:/root/.m2/repository解决问题。
删除lastupdate后缀文件
在root下用cmd执行如下命令可以删除所有的update文件
for /r %i in (*.lastUpdated) do del %i
依赖结构
- 通过一层一层的parent继承,继承母pom。
- 在母pom中通过dependencymanagement的import接口,引入其他三个模块的pom。
JAVA相关
密码
长期密码(master/longterm key)是不能在网络上传输的,只有短期密码(session/shortterm key)才允许在网络上传输。原来如此才有session这个词。
证书
证书的本质,就是两个东西,一个是持证人的公钥明文(既能加密,又能解密),还有一个就是证书发放机构CA用自己的私钥加密过的前面所说明文的摘要。
所以所有的持证人都会有一个CA的证书和一个自己的证书,这个CA的证书里面自然是CA的公钥,可以用来解密其他人的证书,判断其是本人,然后用其证书里面的公钥进行加密约定的对称密钥,发回去。
我们可以看出,证书的本质就是当做一个公钥用的。里面的摘要是CA验证说这个这个证书我授权了,这个机构有资格拿这个证书。但是CA的证书也是需要认证的,这么一层一层网上传,最上面的证书总会没有人给他认证的,它就可以自己给自己认证,用自己的私钥加密自己的公钥。
这种证书的持证人,就只会有一个证书,没有CA的证书。这样的话,通信是安全的,因为你收到他的证书后,用证书里的公钥(代替了CA证书里的公钥)去解密摘要,判断是持证人本人。只是这种证书没有CA背书去审核这个持证人的资质等公司经营状况的信息。
keystore
keystore是java特有的存储证书的文件,里面可以一条一条的存储两种类型的文件,
- 一种是证书,也就是公钥(可信任的证书实体(trusted certificate entries))。
- 一种是公钥和私钥对(密钥实体(Key entity))。可以使用keytool的命令来查看
keytool -list -v -keystore xxxx
keystore本身有一个storepassword,用于访问。
修改使用keytool -storepasswd -keystore xxxx
keystore里面的私钥公钥对如果想要被访问,需要有私钥的密码,这个是keypassword。(keytool本身是不能看到私钥的,只能去改变私钥的keypassword)
修改使用./keytool -keypasswd -alias com.huawei.cmp.serverkey -keystore xxxx.
这里面有一个坑,要是你的keypasswd和storepasswd一样的话,修改keypasswd的时候,只会提示你输入storepasswd,而不要求你输入keypasswd。
线程
Callable接口,就是在runnable接口的基础上,把run()方法编程了call()方法。在方法里面,利用泛型的约束,要求了必须返回一个值罢了。
FutureTask就相当于Thread,只是传入类必须实现callable而不是Thread对应的runnable,而且在Thread的基础上,通过泛型,约束了返回值必须和callable的返回值相一致。拥有的方法也比thread要多。
FutureTask<String> ft = new FutureTask<String>(callable1);
锁
ReentrantLock,以及各种Atomic类都是java5之后引入的,其本身是通过类的方式实现,而不是JVM的关键字。
所以在使用上,多了很多定制的功能,比如可以设置没拿到锁时的等待时间,但是呢,优化不如sychronized好 。
所以,资源竞争不激烈的时候,用sychronized性能最强。
资源竞争激烈时,如果配置的好,ReentrantLock,以及各种Atomic类可能会提升性能,但是!!!如果用的不好,不仅不能提高性能,还可能带来灾难。
postcontruct注解
如果想在生成对象时候完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。(就是某些初始化需要依赖注入进来的类,这样你就没办法在构造器里完成,所以你需要依靠postconstruct注解)
Constructor >> @Autowired >> @PostConstruct
举个例子:
public Class AAA {
@Autowired
private BBB b;
public AAA() {
System.out.println("此时b还未被注入: b = " + b);
}
@PostConstruct
private void init() {
System.out.println("@PostConstruct将在依赖注入完成后被自动调用: b = " + b);
}
}
Could not initialize class
java.lang.NoClassDefFoundError: Could not initialize class
JVM在加载类的时候,会初始化静态变量和执行静态代码块,如果加载失败,以后再用到这个类,就会报上面那个无法初始化类的错误。(区别于无法找到类的错误。)
比如下面这种类,就无法初始化成功。
class ClassWithInitErrors{
static int data = 1 / 0;
}
第一次和第二次的报错也不一样
第一次new会报:java.lang.ExceptionInInitializerError
第二次new会报:java.lang.NoClassDefFoundError: Could not initialize class ClassWithInitErrors
Docker
Docker的本质是轻量虚拟化(就比原来的程序多了一点硬盘)、资源隔离。
如果在一个容器里装多个软件,除了省一点硬盘外没有什么意义,还有坏处:
- docker外只能监控主线程,所以一个容器装多个软件,还是只能监控一个线程。其他线程挂了都不知道。
- 无法实现部件的弹性扩展,要扩展又是一整个一套全部得复制。
- 除主线程外的其他线程都没有办法暴露出来给其他容器使用。
docker的正确玩法,是每个容器装一个软件,然后通过k8s或者docker compose去进行容器编排。
强制类型转换的坑
JAVA强制类型转换的时候,在编译期间,只会校验是否有继承的关系而已!!!不会去校验继承关系的顺序,也不会去校验实现关系!!!
也就是说,父类强转成子类,以及某个类强转成任何接口,都不会在编译时报错。只会在运行时报错。
比较典型的例子,object对象,可以在编译期强转成任何对象(因为它本身是所有对象的父类)、以及任何接口。却不会报错。。。。这是个巨坑呀。所以代码编译过了,不一定就是对的。
下列错误代码在编译器里面不会报错。
Object object=new Object();
ControllerUploadCtx wrong1=(ControllerUploadCtx)object;
Map wrong2=(Map)object;
还有一种很坑的应用场景。
像eat( Map m )这种接受接口的方法,在编译时,任何对象都可以通过eat((Map)xxx )的强转方式,接受到任何的对象。。。即使这个对象没有实现Map接口,在编译时都会被报错。
看到强转一定要分外留心:
-
强转为接口类型:
我们一般都没看到过强转成接口的。是因为你接口肯定是类的上层,像
HashMap hashMap = new HashMap() ; Map a = hashMap;
根本就不需要写成Map a = (Map)hashMap; 因为没有必要。所以我们基本就看不到强制转换成接口的。
如果你发现了有这种强转为接口的使用,就要分外小心了。因为对的时候它没必要,错的时候它还不会编译报错。
-
强转为类类型:
有继承关系之间的类的强转,能转换的没问题,不能转换的情况下,在编译时也不会报错。
常用的GIT命令
git remote -v
git remote add team ssh://git@isource-nj.huawei.com:2222/CloudOps/package.git
git pull <远程主机名> <远程分支名>:<本地分支名>
git push <远程主机名> <本地分支名>:<远程分支名>
git cherry-pick <cmmmit-id>
Git在reset时,会删除一些文件,但是有的时候目录或者工程不会被删除,这可能是因为这些工程本身没有被加入到git的同步列表中。但是这种目录结构会导致你的目录结构跟实际情况不一样。这样的话使用gittortoise工具cleanup一下就好。然后在idea里面rebuild一下。