派大星的博客

很多事情不是会了才能做,而是做了才能学会


  • 首页

  • 标签

  • 分类

  • 关于

  • 搜索

自定义类加载器实现代码热替换

发表于 2019-01-16 | 分类于 Java

代码热替换,在不重启服务器的情况下可以修改类的代码并使之生效

1. 自定义类加载器

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.pibgstar.demo.java;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Set;

/**
* @author pibigstar
* @desc 代码热替换,在不重启服务器的情况下可以修改类的代码并使之生效
**/
public class MyClassLoader extends ClassLoader{
// 定义.class路径
private String swapPath;
// 存储哪些类需要我自身去加载
private Set<String> myselfLoader;

public MyClassLoader(String swapPath, Set<String> myselfLoader) {
this.swapPath = swapPath;
this.myselfLoader = myselfLoader;
}

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> loadedClass = findLoadedClass(name);
// 需要我自己去加载
if (loadedClass==null && myselfLoader.contains(name)) {
loadedClass = findClass(name);
if (loadedClass!=null){
return loadedClass;
}
}
return super.loadClass(name, resolve);
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 根据文件系统路径加载class文件,并返回byte数组
byte[] b = getClassByte(name);
// 调用ClassLoader提供的方法,将二进制数组转换成Class类的实例
return defineClass(name,b,0,b.length);
}

private byte[] getClassByte(String name) {
String className = name.substring(name.lastIndexOf(".")+1,
name.length()) + ".class";
try {
FileInputStream fis = new FileInputStream(swapPath + className);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int length = 0;
while ((length=fis.read(buff))>0){
baos.write(buff,0,length);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return new byte[]{};
}
}

2. 测试

自定义一个每2秒打印调用一次方法打印版本号,先编译一次版本号为2的 MyClassLoaderTest .class类,然后启动版本号为1的,在运行过程中,我们把版本号为1的MyClassLoaderTest .class类替换成版本号为2的MyClassLoaderTest .class类,我们发现控制台立马输出了版本号2

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
27
28
29
30
31
32
package com.pibgstar.demo.java;
import com.google.common.collect.Sets;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author pibigstar
* @desc
**/
public class MyClassLoaderTest {
public void printVersion() {
System.out.println("版本号1");
}
public static void main(String[] args){
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// target/classes/com/pibgstar/demo/java/swap/
String swapPath = MyClassLoader.class.getResource("").getPath();
String className = "com.pibgstar.demo.java.MyClassLoaderTest";
// 创建自定义的类加载器,将路径和需要我们自己去加载的类名传递进去
MyClassLoader myClassLoader = new MyClassLoader(swapPath, Sets.newHashSet(className));
try {
//使用自定义的ClassLoader加载类,并调用printVersion方法。
Object o = myClassLoader.loadClass(className).newInstance();
o.getClass().getMethod("printVersion").invoke(o);
} catch (Exception e) {
e.printStackTrace();
}
}
},0,2000);
}
}

3. 结果截图

常用工具学习之curl

发表于 2019-01-16 | 分类于 tools

@[toc]

1. 下载安装

1
yum install -y curl

1.1 查看文档

1
curl --help

1.2 参数说明

  • -X 更换请求
  • -o 保存网页
  • -i 显示response信息
  • -L 302跳转网页
  • --header 设置header
  • --user-agent 设置userAgent
  • --cookie 设置cookie

2. 常用操作

2.1 更换请求类型

默认是GET请求,通过 -X 参数 来更换其他请求

1
curl -X POST www.baidu.com

2.2 POST数据

通过 --data参数来设置请求参数

1
curl -X POST --data "username=123&password=456" www.baidu.com

对数据进行URL编码

1
curl -X POST --data-urlencode "username=123&password=456" www.baidu.com

2.3 设置userAgent

1
curl --user-agent "Mozilla/5.0 (Windows NT 10.0; WOW64) ..." www.baidu.com

2.4 设置cookie

1
curl --cookie "token=xxx&skey=123" www.baidu.com

2.5 设置header

1
curl --header "Content-Type:application/json" www.baidu.com

2.6 保存网页内容

1
curl -o www.baidu.com

2.7 显示Response头信息

1
curl -i www.baidu.com

2.8 跳转网页

如果目标地址为302,则跳转到新地址

1
curl -L www.baidu.com

git commit msg格式规范校验

发表于 2019-01-14 | 分类于 工具使用,git

@[toc]

1. commit规范

每个公司的规范都是不同的,这里讲下我常用的规范
type(模块): message

type

用于说明 commit的类别,只允许使用下面7个标识。

  • feat:新功能(feature)
  • fix:修补bug
  • hotfix:紧急修复bug
  • test:增加测试
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • chore:构建过程或辅助工具的变动

举个例子,我新增了用户登录功能,那么提交信息应该这样写:

1
git commit -m "feat(user): add the user login"

2. 使用git hooks校验

在.git/hooks目录下有很多钩子,我们可以根据需要自定义不同的内容,这里我们只需要修改commit-msg即可。

首先将commit-msg.sample 改为 commit-msg,也就是去掉后缀。
将里面的内容修改为下面内容

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
MSG=`awk '{printf("%s",$0)}' $1`
if [[ $MSG =~ ^(feat|fix|test|refactor|docs|style|chroe)\(.*\):.*$ ]]
then
echo -e "\033[32m commit success! \033[0m"
else
echo -e "\033[31m Error: the commit message is irregular \033[m"
echo -e "\033[31m Error: type must be one of [feat,fix,docs,style,refactor,test,chore] \033[m"
echo -e "\033[31m eg: feat(user): add the user login \033[m"
exit 1
fi

当我们提交不规范的commit信息时就会提醒用户,并终止此提交

3. gitlab ci 中校验

3.1 .gitlab-ci.yml

1
2
3
4
5
6
7
8
9
stages:
- lint

commit_msg:
stage: lint
script:
- /bin/bash commit-msg.sh
only:
- pushes

3.2 commit-msg.sh

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
27
28
29
30
31
32
33
34
35
#! /bin/bash

# get commit msg
if [[ $CI_COMMIT_MESSAGE ]]; then
msg=$CI_COMMIT_MESSAGE
else
read msg < .git/COMMIT_EDITMSG
fi

echo -e "\033[33m The commit msg: \033[0m $msg"

# if the msg is merge then skip it
mergePattern='^Merge '
if [[ $msg =~ $mergeCommitPattern ]]; then
echo -e "\033[32m skip the merge, commit success! \033[0m"
exit 0
fi

# check the commit msg
maxLength=50
length=${#msg}
pattern='^(feat|fix|hotfix|test|refactor|docs|style|chroe)\(.*\):.*$'

if [[ $msg =~ $pattern ]]; then
if [[ $length -gt $maxLength ]]; then
echo -e "\033[31m Error: the msg over max length \033[m"
exit 1
fi
echo -e "\033[32m commit success! \033[0m"
else
echo -e "\033[31m Error: the commit message is irregular \033[m"
echo -e "\033[31m Error: type must be one of [feat,fix,hotfix,docs,style,refactor,test,chore] \033[m"
echo -e "\033[31m eg: feat(user): add the user login \033[m"
exit 1
fi

docker打包springboot项目成镜像

发表于 2019-01-02 | 分类于 工具使用,docker

[TOC]

1. 项目结构

项目结构

2. 创建Dockerfile文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 拉取基础镜像
FROM 139.199.64.253:5000/java
# 维者信息
MAINTAINER pibigstar

# 将JDK复制到镜像中,如果镜像已经有了JDK环境则无需配置此项和下面的运行环境
# COPY jdk1.7.0_79 /usr/local/jdk1.7.0_79
# 配置运行环境
# ENV JAVA_HOME=/usr/local/jdk1.7.0_79
# ENV PATH=$JAVA_HOME/bin:$PATH
# ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

# 添加springboot项目到镜像中的home目录,并重命名为app.jar
ADD parsevip-0.0.1-SNAPSHOT.jar ~/app.jar

# 告诉Docker服务端暴露的端口,在容器启动时需要通过 -p 做端口映射
EXPOSE 8080

# 容器启动后执行的命令
ENTRYPOINT ["java","-jar","~/app.jar"]

##3. 编译镜像

1
docker build -t 镜像名 .

.代表为当前路径
这里写图片描述

##4. 运行镜像

1
docker run -d -p 139.199.64.253:8080:8080 --name 容器名 镜像名

这里写图片描述

##5. 查看容器运行日志

1
docker logs -f parsevip

docker搭建本地仓库并制作自己的镜像

发表于 2018-12-31 | 分类于 工具使用,Linux,docker

[TOC]

1. 搭建本地仓库

1.1 下载仓库镜像

1
docker pull registry

1.2 启动仓库容器

1
docker run -d -p 5000:5000 -v /home/registry/:/tmp/registry registry

第一个5000是本地的端口,第二个5000是docker里面的端口,将本地5000的端口映射到
docker里面的5000端口

2. 在CentOS容器中安装JDK

2.1 下载CentOS容器

镜像仓库地址:https://dashboard.daocloud.io/packages/explore

1
docker pull daocloud.io/library/centos:latest

2.2 运行Linux容器:

1
docker run -d -it --name myCentos 镜像ID /bin/bash
  • *-d 后台运行 *
  • –name 容器名

2.3 将JDK复制到myCentos容器中

1
docker cp jdk-10.0.1_linux-x64_bin.tar.gz myCentos:/usr/local

2.4 进入容器

1
docker exec -it myCentos /bin/bash

2.5 解压JDK

1
tar -zxvf jdk-10.0.1_linux-x64_bin.tar.gz

2.6 配置环境变量

1
vi /etc/profile

在文件末尾添加:
export JAVA_HOME=/usr/local/jdk1.8.0_152
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

2.6.1 刷新环境变量

1
source /etc/profile

2.6.2 设置开机自动执行source

1
vi ~/.bashrc

在第一行添加 source /etc/profile

2.6.3 重启容器

1
2
docker stop myCentos
docker start myCentos

2.7 将容器提交到镜像里

1
docker commit <CONTAINERID> <IMAGE>

将容器提交到镜像中

3. 将新制作的镜像推送到仓库中

3.1 修改tag

1
docker tag <REPOSITORY>  仓库IP地址:端口/镜像名

tag名应该为 ip:端口/镜像名 的形式,它会将此镜像推送到此IP地址下的仓库,并且定义此镜像名

3.2 将镜像推送到仓库中

1
docker push tag名

可通过http://139.199.64.253:5000/v2/_catalog地址访问你上传的结果

注意:如果push报错:The push refers to a repository [139.199.64.253:5000/java]
Get https://139.199.64.253:5000/v1/_ping: http: server gave HTTP response to HTTPS client
则修改 /etc/docker 路径下的 daemon.json 文件,如果没有则手动创建,在文件中写入:
{ “insecure-registries”:[“139.199.64.253:5000”] }
然后重启docker: service docker restart
重新启动仓库:docker run -d -p 5000:5000 -v /home/registry/:/tmp/registry registry

如果想推送到docker的中央仓库则 tag名改为 : docker.io/java 然后再推送即可

Java生成MD5的两种方式

发表于 2018-12-31 | 分类于 工具使用,Java,java工具类

1 原生的

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
27
28
29
30
31
package com.pibigstar.common.utils;

import java.security.MessageDigest;

/**
* MD5加密工具类
* @author pibigstar
*
*/
public class MyMD5Util {
//盐,用于混交md5
private static final String slat = "&%5123***&&%%$$#@";
public static String encrypt(String dataStr) {
try {
dataStr = dataStr + slat;
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(dataStr.getBytes("UTF8"));
byte s[] = m.digest();
String result = "";
for (int i = 0; i < s.length; i++) {
result += Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6);
}
return result;
} catch (Exception e) {
e.printStackTrace();
}

return "";
}

}

2 使用Spring中的工具类

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
package com.pibigstar.common.utils;

import org.springframework.util.DigestUtils;

import com.pibigstar.common.Constant;

/**
* MD5工具类
* @author pibigstar
*
*/
public class MD5Util {
//盐,用于混交md5
private static final String slat = "&%5123***&&%%$$#@";
/**
* 生成md5
* @param seckillId
* @return
*/
public static String getMD5(String str) {
String base = str +"/"+slat;
String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
return md5;
}

}

获取所有QQ好友列表以及好友信息

发表于 2018-12-31 | 分类于 爬虫相关,Java

完整源码下载

点击下载完整源码
如果对你有用,请给个Star,你的支持,是我最大的动力

1 获取所有QQ

这里主要通过抓包,抓取QQ空间中的数据
记得将访问空间权限改为QQ好友

接口地址:
https://h5.qzone.qq.com/proxy/domain/base.qzone.qq.com/cgi-bin/right/get_entryuinlist.cgi?uin=741047261&fupdate=1&action=1&offset=0&g_tk=847821819&qzonetoken=24dd9cbc92e1ba657addcd982f7f4d0fa1a9ee8ba7b8d52863703a10274f08f9325d1298e5afac11

这里uin 为你的QQ号
offset 偏移量 ,每次增加 50 即可
g_tk是从cookie中获取的 p_skey 再通过算法获得;

java版实现此算法:

1
2
3
4
5
6
7
8
9
10
11
public class GetTk {

public static String getTk(String skey) {
int hash = 5381;
for(int i = 0, len = skey.length(); i < len; ++i){
hash += (hash << 5) + (int)(char)skey.charAt(i);
}
return (hash & 0x7fffffff)+"";
}

}

完整版java实现:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.pibigstar.qq.main;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import com.pibigstar.qq.domain.User;
import com.pibigstar.qq.utils.GetCookies;
import com.pibigstar.qq.utils.GetTk;
import com.pibigstar.qq.utils.JSONUtil;

/**
* 获取所有的QQ用户列表
* @author pibigstar
*
*/
public class GetAllUser {

public static List<User> getAll(Map<String, String> cookies) throws IOException{
List<User> allUser = new ArrayList<>();
String qq = cookies.get("o_cookie");
String pskey = cookies.get("p_skey");

String g_tk = GetTk.getTk(pskey);

for(int i=0;;) {
Document document = Jsoup.connect("https://h5.qzone.qq.com/proxy/domain/base.qzone.qq.com/cgi-bin/right/get_entryuinlist.cgi?uin=741047261&fupdate=1&action=1&offset="+i+"&g_tk="+g_tk).cookies(cookies).header("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36").timeout(10000).ignoreContentType(true).get();
String strJson = document.getElementsByTag("body").text().replace("_Callback(", "").replace(");", "");
JSONObject jsonObject = new JSONObject(strJson);
String jsonData =((JSONObject) jsonObject.get("data")).get("uinlist").toString();
List<User> users = JSONUtil.JSONToList(jsonData, User.class);
if (users==null||users.size()==0) {
break;
}
allUser.addAll(users);
i+=50;
}
return allUser;
}

}

2 获得QQ信息

接口地址:
http://cgi.find.qq.com/qqfind/buddy/search_v3

post请求,需要两个参数:
keyword : 你要查询的QQ号码
lwd : g_tk 值

注意:此g_tk 的值为 cookie中 skey 计算得来的 而不是 p_skey

java实现

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.pibigstar.qq.main;

import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import com.pibigstar.qq.domain.User;
import com.pibigstar.qq.utils.GetTk;
import com.pibigstar.qq.utils.JSONUtil;

public class GetInfo{
public static User getInfo(String qq,Map<String, String> cookies) {

User user = new User();
Map<String, String> data = new HashMap<>();
//注意这里,获得信息是用的skey 而获得全部好友使用的为p_skey
String skey = cookies.get("skey");
String g_tk = GetTk.getTk(skey);

data.put("keyword", qq);
data.put("ldw", g_tk);

Document document;
try {
document = Jsoup.connect("http://cgi.find.qq.com/qqfind/buddy/search_v3").cookies(cookies).header("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36").ignoreContentType(true).data(data).timeout(10000).post();
String allJson = document.getElementsByTag("body").text();
System.out.println(allJson);
JSONObject result = (JSONObject) new JSONObject(allJson).get("result");
JSONObject buddy = (JSONObject) result.get("buddy");
JSONArray jsonArray = buddy.getJSONArray("info_list");

JSONObject dataJson = (JSONObject) jsonArray.get(0);
user = JSONUtil.jSONToObject(dataJson.toString(), User.class);
JSONObject birthdayJson = (JSONObject) dataJson.get("birthday");
String year = birthdayJson.get("year").toString();
String month = birthdayJson.get("month").toString();
String day = birthdayJson.get("day").toString();
String birthday = year+"-"+month+"-"+day;
user.setBirthday(birthday);

Calendar calendar = Calendar.getInstance();
int now = calendar.get(Calendar.YEAR);

if (year!=null&&year.length()>0) {
int age = now - Integer.parseInt(year);
user.setAge(age);
}
} catch (IOException e) {
e.printStackTrace();
}
return user;
}

}

把user的bean也放一下

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package com.pibigstar.qq.domain;

public class User {

private String data;//QQ号

private String label;//用户名/备注名

private String nick;//昵称

private String gender;//性别 1为男 2为女

private String city;//城市

private String country;//国家

private String lnick;//个性签名

private String personal;//个人说明

private String college;//学校

private String birthday;//生日

private String email;//邮箱

private String phone;//手机

private String uin;//qq号

private int age;


public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getUin() {
return uin;
}

public void setUin(String uin) {
this.uin = uin;
}

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}

public String getLabel() {
return label;
}

public void setLabel(String label) {
this.label = label;
}

public String getNick() {
return nick;
}

public void setNick(String nick) {
this.nick = nick;
}

public String getGender() {
return gender;
}

public void setGender(String gender) {
this.gender = gender;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

public String getCountry() {
return country;
}

public void setCountry(String country) {
this.country = country;
}

public String getLnick() {
return lnick;
}

public void setLnick(String lnick) {
this.lnick = lnick;
}

public String getPersonal() {
return personal;
}

public void setPersonal(String personal) {
this.personal = personal;
}

public String getCollege() {
return college;
}

public void setCollege(String college) {
this.college = college;
}

public String getBirthday() {
return birthday;
}

public void setBirthday(String birthday) {
this.birthday = birthday;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}

@Override
public String toString() {
return "User [data=" + data + ", label=" + label + ", nick=" + nick + ", gender=" + gender + ", city=" + city
+ ", country=" + country + ", lnick=" + lnick + ", personal=" + personal + ", college=" + college
+ ", birthday=" + birthday + ", email=" + email + ", phone=" + phone + "]";
}


}
1…1314
派大星

派大星

137 日志
64 分类
230 标签
GitHub CSDN
© 2019 派大星