java 运行 加载jar,java运行时加载额外的 jar 包或 class

首先讲下java类加载的顺序

f26118bafd395c111bc7e6aca1cc2c75.png

每个类加载器有自己的名字空间,对于同一个类加载器实例来说,名字相同的类只能存在一个,并且仅加载一次。不管该类有没有变化,下次再需要加载时,它只是从自己的缓存中直接返回已经加载过的类引用。

接下来讲如何加载外部jar

首先要有一个工程外的jar包,这里假定有个Test.jar,里面有个com.chentaoqian.test.Test类。

使用系统类加载器,加载一个jar

Java

package com.chentaoqian.classloaderdemo;

import java.io.File;

import java.lang.reflect.Method;

import java.net.URL;

import java.net.URLClassLoader;

public class MyClassloader {

public static void classLoader(File file, String className, String methodName, Object[] args, Class>[] parameterTypes) {

try {

URL url = file.toURI().toURL();

//得到系统类加载器,利用该加载器加载指定路径下的jar包

URLClassLoader urlClassLoader= (URLClassLoader) ClassLoader.getSystemClassLoader();

Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{ URL.class});

add.setAccessible(true);

add.invoke(urlClassLoader, new Object[] {url});

urlClassLoader.loadClass(className);

Class> c = urlClassLoader.loadClass(className);

//列出所有方法

// Method[] methods = c.getMethods();

// for (Method m : methods) {

// System.out.println(m.getName());

// }

//调用方法

// if (args == null) {

// c.getMethod(methodName, parameterTypes).invoke(c.newInstance());

// } else {

// c.getMethod(methodName, parameterTypes).invoke(c.newInstance(), args);

// }

// urlClassLoader.close();

} catch (Exception e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

//无参方法的例子

classLoader(new File("E:\\TestJar.jar"), "com.chentaoqian.test.Test", "sayHi", null, null);

//有参方法的例子

classLoader(new File("E:\\TestJar.jar"), "com.chentaoqian.test.Test", "sayBye", new String[]{"byebye"}, new Class>[]{String.class});

}

}

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

packagecom.chentaoqian.classloaderdemo;

importjava.io.File;

importjava.lang.reflect.Method;

importjava.net.URL;

importjava.net.URLClassLoader;

publicclassMyClassloader{

publicstaticvoidclassLoader(Filefile,StringclassName,StringmethodName,Object[]args,Class>[]parameterTypes){

try{

URLurl=file.toURI().toURL();

//得到系统类加载器,利用该加载器加载指定路径下的jar包

URLClassLoaderurlClassLoader=(URLClassLoader)ClassLoader.getSystemClassLoader();

Methodadd=URLClassLoader.class.getDeclaredMethod("addURL",newClass[]{URL.class});

add.setAccessible(true);

add.invoke(urlClassLoader,newObject[]{url});

urlClassLoader.loadClass(className);

Class>c=urlClassLoader.loadClass(className);

//列出所有方法

//          Method[] methods = c.getMethods();

//          for (Method m : methods) {

//              System.out.println(m.getName());

//          }

//调用方法

//          if (args == null) {

//              c.getMethod(methodName, parameterTypes).invoke(c.newInstance());

//          } else {

//              c.getMethod(methodName, parameterTypes).invoke(c.newInstance(), args);

//          }

//          urlClassLoader.close();

}catch(Exceptione){

e.printStackTrace();

}

}

publicstaticvoidmain(String[]args){

//无参方法的例子

classLoader(newFile("E:\\TestJar.jar"),"com.chentaoqian.test.Test","sayHi",null,null);

//有参方法的例子

classLoader(newFile("E:\\TestJar.jar"),"com.chentaoqian.test.Test","sayBye",newString[]{"byebye"},newClass>[]{String.class});

}

}

使用jdk自带的classloader,可以正确的加载jar包中的指定class,但如果要加载单独的一个class文件,则会报错。

使用自定义类加载器,加载一个class

通过编写一个类继承自ClassLoader,并重写findClass方法

package com.chentaoqian.classloaderdemo;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

public class MyClassloader2 extends ClassLoader {

private String fileName;

public MyClassloader2(String fileName) {

this.fileName = fileName;

}

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

File file = new File(fileName);

try {

FileInputStream fis = new FileInputStream(file);

ByteArrayOutputStream bos = new ByteArrayOutputStream();

int len = 0;

while ((len = fis.read()) != -1) {

bos.write(len);

}

byte[] data = bos.toByteArray();

fis.close();

bos.close();

return defineClass(name, data, 0, data.length);

} catch (Exception ex) {

ex.printStackTrace();

}

return super.findClass(name);

}

}

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

packagecom.chentaoqian.classloaderdemo;

importjava.io.ByteArrayOutputStream;

importjava.io.File;

importjava.io.FileInputStream;

publicclassMyClassloader2extendsClassLoader{

privateStringfileName;

publicMyClassloader2(StringfileName){

this.fileName=fileName;

}

@Override

protectedClass>findClass(Stringname)throwsClassNotFoundException{

Filefile=newFile(fileName);

try{

FileInputStreamfis=newFileInputStream(file);

ByteArrayOutputStreambos=newByteArrayOutputStream();

intlen=0;

while((len=fis.read())!=-1){

bos.write(len);

}

byte[]data=bos.toByteArray();

fis.close();

bos.close();

returndefineClass(name,data,0,data.length);

}catch(Exceptionex){

ex.printStackTrace();

}

returnsuper.findClass(name);

}

}

package com.chentaoqian.classloaderdemo;

import java.lang.reflect.Method;

public class ClassloaderTest {

public static void main(String[] args) {

MyClassloader2 myClassloader = new MyClassloader2("E:\\Test.class");

try {

//加载class文件

Class> c = myClassloader.loadClass("com.chentaoqian.test.Test");

if(c != null){

try {

Object obj = c.newInstance();

// Method method = c.getDeclaredMethod("sayHi", null);

Method method = c.getMethod("sayHi", null);

//通过反射调用Test类的say方法

method.invoke(obj, null);

} catch (Exception e) {

e.printStackTrace();

}

}

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

}

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

packagecom.chentaoqian.classloaderdemo;

importjava.lang.reflect.Method;

publicclassClassloaderTest{

publicstaticvoidmain(String[]args){

MyClassloader2myClassloader=newMyClassloader2("E:\\Test.class");

try{

//加载class文件

Class>c=myClassloader.loadClass("com.chentaoqian.test.Test");

if(c!=null){

try{

Objectobj=c.newInstance();

//                    Method method = c.getDeclaredMethod("sayHi", null);

Methodmethod=c.getMethod("sayHi",null);

//通过反射调用Test类的say方法

method.invoke(obj,null);

}catch(Exceptione){

e.printStackTrace();

}

}

}catch(ClassNotFoundExceptione){

e.printStackTrace();

}

}

}

这种方式可以正确加载class文件。需要注意的是:若该class文件使用了extends,则加载会报错,因为父类找不到。