1.自定义类加载器的作用
其实就是对已经加密的class解密,再加载到虚拟机中
2.生成加密的class文件
-
被加密的java文件
public interface IUserDao { void save(); } public class UserDao implements IUserDao { @Override public void save() { System.out.print("save method."); } }
-
加密工具类
public final class DesUtils { private static final String DES = "DES"; private static final String KEY = "4YztMHI7PsT4rLZN"; private DesUtils() {} public static byte[] encode(byte[] bytes) { try { return encrypt(bytes, KEY.getBytes()); } catch (Exception e) { throw new RuntimeException("encode bytes error."); } } public static byte[] decode(byte[] bytes) { try { return decrypt(bytes, KEY.getBytes()); } catch (Exception e) { throw new RuntimeException("decode bytes error."); } } private static byte[] encrypt(byte[] src, byte[] key) throws Exception { SecureRandom sr = new SecureRandom(); DESKeySpec dks = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey secretKey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance(DES); cipher.init(Cipher.ENCRYPT_MODE, secretKey, sr); return cipher.doFinal(src); } private static byte[] decrypt(byte[] src, byte[] key) throws Exception { SecureRandom sr = new SecureRandom(); DESKeySpec dks = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey secretKey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance(DES); cipher.init(Cipher.DECRYPT_MODE, secretKey, sr); return cipher.doFinal(src); } private static String byte2hex(byte[] b) { StringBuilder hs = new StringBuilder(); String temp; for (int n = 0; n < b.length; n++) { temp = (Integer.toHexString(b[n] & 0XFF)); if (temp.length() == 1) { hs.append("0").append(temp); } else { hs.append(temp); } } return hs.toString().toUpperCase(); } private static byte[] hex2byte(byte[] b) { if ((b.length % 2) != 0) { throw new IllegalArgumentException("length not even"); } byte[] b2 = new byte[b.length / 2]; for (int n = 0; n < b.length; n += 2) { String item = new String(b, n, 2); b2[n / 2] = (byte) Integer.parseInt(item, 16); } return b2; } }
-
生成加密class文件
public static void createEncodeFile() { String targetFilePath = "D:\\test\\target\\classes\\test\\UserDao.class"; String encodedFilePath = "D:\\test\\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; 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) {} } } }
3.自定义类加载器
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();
}
}
}
}
4.测试
public static void main(String[] args) throws Exception {
EncodeClassLoader classLoader = new EncodeClassLoader();
String filePath = "D:\\test\\";
String name = "test.UserDao";
try {
Class<IUserDao> userDaoClass = (Class<IUserDao>) classLoader.findClassByFilePathAndName(filePath, name);
IUserDao userDao = userDaoClass.newInstance();
userDao.save();
} catch (Exception e) {
e.printStackTrace();
}
}