1.简介
通过加密的.class文件,并将其加载到JVM中,然后再调用其方法。
2.小栗子源码
//生成的.class文件将要被加密
public class UserDao implements IUserDao {
@Override
public void save(User user) {
System.out.print("save user.");
}
}
// 生成加密的.class文件
@Test
public void createEncodeFile() {
String targetFilePath = "C:\\MineProjects\\JavaDemo\\target\\classes\\com\\boomsecret\\classloader\\encode\\UserDao.class";
String encodedFilePath = "C:\\MineProjects\\JavaDemo\\UserDao.class";
FileInputStream fis = null;
FileOutputStream fos = null;
ByteArrayOutputStream baos = null;
try {
fis = new FileInputStream(new File(targetFilePath));
fos = new FileOutputStream(new File(encodedFilePath));
baos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len = -1;
while ((len = fis.read(bytes)) != -1) {
baos.write(bytes, 0, len);
}
byte[] encode = DesUtils.encode(baos.toByteArray());
fos.write(encode);
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (Objects.nonNull(fis)) {
try {
fis.close();
} catch (Exception e) {}
}
if (Objects.nonNull(fos)) {
try {
fos.close();
} catch (Exception e) {}
}
if (Objects.nonNull(baos)) {
try {
baos.close();
} catch (Exception e) {}
}
}
}
// 类加载器
public class EncodeClassLoader extends ClassLoader {
private String filePath = null;
protected Class<?> findClassByFilePathAndName(String filePath, String name)
throws ClassNotFoundException {
if (Objects.isNull(filePath) || Objects.isNull(name)) {
throw new IllegalArgumentException("参数错误");
}
this.filePath = filePath;
return findClass(name);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
StringBuilder stringBuilder = new StringBuilder(filePath)
.append(name.substring(name.lastIndexOf(".") + 1))
.append(".class");
FileInputStream fis = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
fis = new FileInputStream(new File(stringBuilder.toString()));
byte[] bytes = new byte[1024];
int len = -1;
while ((len = fis.read(bytes)) != -1) {
baos.write(bytes, 0, len);
}
byte[] decodeBytes = DesUtils.decode(baos.toByteArray());
return this.defineClass(name, decodeBytes, 0, decodeBytes.length);
} catch (Exception e) {
throw new ClassNotFoundException();
} finally {
closeStream(fis);
closeStream(baos);
}
}
private void closeStream(OutputStream stream) {
if (Objects.nonNull(stream)) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void closeStream(InputStream stream) {
if (Objects.nonNull(stream)) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.测试
@Test
public void loadEncodeFile() {
EncodeClassLoader classLoader = new EncodeClassLoader();
String filePath = "C:\\MineProjects\\JavaDemo\\";
String name = "com.boomsecret.classloader.encode.UserDao";
try {
Class<IUserDao> userDaoClass = (Class<IUserDao>) classLoader.findClassByFilePathAndName(filePath, name);
IUserDao userDao = userDaoClass.newInstance();
userDao.save(new User());
} catch (Exception e) {
e.printStackTrace();
}
}
result:
save user.
4.总结
像Android的热更新,应该用的类似的原理。总之,类加载器这一块还是有很多东西要看的。
源码地址:https://gitee.com/jsjack_wang/JavaDemo
网友评论