Java中动态加载jar文件和class文件
概述
诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下的jar文件以及classes目录下的class文件,另外像spring这类框架,也可以根据指定的路径扫描并加载指定的类文件,这个技术可以实现一个容器,容纳各类不同的子应用。
Java类由于需要加载和编译字节码,动态加载class文件较为麻烦,不像C加载动态链接库只要一个文件名就可以搞定,但JDK仍提供了一整套方法来动态加载jar文件和class文件。
动态加载jar文件
[java] view plaincopy在CODE上查看代码片派生到我的代码片
1. // 系统类库路径
2. File libPath = new File(jar文件所在路径);
3.
4. // 获取所有的.jar和.zip文件
5. File[] jarFiles = libPath.listFiles(new FilenameFilter() {
6. public boolean accept(File dir, String name) {
7. return name.endsWith(".jar") || name.endsWith(".zip");
8. }
9. });
10.
11. if (jarFiles != null) {
12. // 从URLClassLoader类中获取类所在文件夹的方法
13. // 对于jar文件,可以理解为一个存放class文件的文件夹
14. Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
15. boolean accessible = method.isAccessible(); // 获取方法的访问权限
16. try {
17. if (accessible == false) {
18. method.setAccessible(true); // 设置方法的访问权限
19. }
20. // 获取系统类加载器
21. URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
22. for (File file : jarFiles) {
23. URL url = file.toURI().toURL();
24. try {
25. method.invoke(classLoader, url);
26. LOG.debug("读取jar文件[name={}]", file.getName());
27. } catch (Exception e) {
28. LOG.error("读取jar文件[name={}]失败", file.getName());
29. }
30. }
31. } finally {
32. method.setAccessible(accessible);
33. }
34. }
动态加载class文件
[java] view plaincopy在CODE上查看代码片派生到我的代码片
1. // 设置class文件所在根路径
2. // 例如/usr/java/classes下有一个test.App类,则/usr/java/classes即这个类的根路径,而.class文件的实际位置是/usr/java/classes/test/App.class
3. File clazzPath = new File(class文件所在根路径);
4.
5. // 记录加载.class文件的数量
6. int clazzCount = 0;
7.
8. if (clazzPath.exists() && clazzPath.isDirectory()) {
9. // 获取路径长度
10. int clazzPathLen = clazzPath.getAbsolutePath().length() + 1;
11.
12. Stack stack = new Stack<>();
13. stack.push(clazzPath);
14.
15. // 遍历类路径
16. while (stack.isEmpty() == false) {
17. File path = stack.pop();
18. File[] classFiles = path.listFiles(new FileFilter() {
19. public boolean accept(File pathname) {
20. return pathname.isDirectory() || pathname.getName().endsWith(".class");
21. }
22. });
23. for (File subFile : classFiles) {
24. if (subFile.isDirectory()) {
25. stack.push(subFile);
26. } else {
27. if (clazzCount++ == 0) {
28. Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
29. boolean accessible = method.isAccessible();
30. try {
31. if (accessible == false) {
32. method.setAccessible(true);
33. }
34. // 设置类加载器
35. URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
36. // 将当前类路径加入到类加载器中
37. method.invoke(classLoader, clazzPath.toURI().toURL());
38. } finally {
39. method.setAccessible(accessible);
40. }
41. }
42. // 文件名称
43. String className = subFile.getAbsolutePath();
44. className = className.substring(clazzPathLen, className.length() - 6);
45. className = className.replace(File.separatorChar, '.');
46. // 加载Class类
47. Class.forName(className);
48. LOG.debug("读取应用程序类文件[class={}]", className);
49. }
50. }
51. }
52. }
完成上述两步操作后,即可使用Class.forName来加载jar中或.class文件包含的Java类了。