zoukankan      html  css  js  c++  java
  • URLClassLoader加载class到当前线程类加载器【zt】

    我们知道,Java利用ClassLoader将类载入内存,并且在同一应用中,可以有很多个ClassLoader,通过委派机制,把装载的任务传递给上级的装载器的,依次类推,直到启动类装载器(没有上级类装载器)。如果启动类装载器能够装载这个类,那么它会首先装载。如果不能,则往下传递。当父类为null时,JVM内置的类(称为:bootstrap class loader)就会充当父类。想想眼下的越来越多用XML文件做配置文件或者是描述符、部署符。其实这些通过XML文档描述的配置信息最终都要变成Java类,基实都是通过ClassLoader来完成的。URLClassLoader是ClassLoader的子类,它用于从指向 JAR 文件和目录的 URL 的搜索路径加载类和资源。也就是说,通过URLClassLoader就可以加载指定jar中的class到内存中。

    下面来看一个例子,在该例子中,我们要完成的工作是利用URLClassLoader加载jar并运行其中的类的某个方法。

    首先我们定义一个接口,使所有继承它的类都必须实现action方法,如下:

    public interface ActionInterface {
         public String action();
    }
    完成后将其打包为testInterface.jar文件。

    接下来新建一工程,为了编译通过,引入之前打好的testInterface.jar包。并创建TestAction类,使它实现ActionInterface接口。如下:


    public class TestAction implements ActionInterface {
        public String action() {
             return " com.mxjava.TestAction.action " ;
        }
    }

    完成后将其打包为test.jar,放在c盘根目录下。下面要做的就是利用URLClassLoader加载并运行TestAction的action方法,并将返回的值打印在控制台上。

    新建一工程,引入testInterface.jar包。并创建一可执行类(main方法),在其中加入如下代码:

    URL url = new URL(“file:C: / test.jar”);

    //(还需要添加抛出异常)
    URLClassLoader myClassLoader =   new URLClassLoader( new URL[]   { url } );

    //web程序中 用 URLClassLoader myClassLoader =   new URLClassLoader( new URL[]   { url } , Thread.currentThread().getContextClassLoader());


    Class myClass = myClassLoader.loadClass(“com.mxjava.TestAction”);
    ActionInterface action = (ActionInterface)myClass.newInstance();
    System.out.println(action.action());
      在上面的例子中,首先利用URLClassLoader加载了C:\test.jar包,将其中的com.mxjava.TestAction类载入内存,将其强制转型为testInterface包中的ActionInterface类型,最后调用其action方法,并打印到控制台中。

      执行程序后,在控制台上如期打印出我们想要的内容。但是,事情并没有那么简单,当我们将该代码移动web应用中时,就会抛出异常。原来,Java为我们提供了三种可选择的ClassLoader:
    1. 系统类加载器或叫作应用类加载器 (system classloader or application classloader)
    2. 当前类加载器
    3. 当前线程类加载器

      在上例中我们使用javac命令来运行该程序,这时候使用的是系统类加载器 (system classloader)。这个类加载器处理 -classpath下的类加载工作,可以通过ClassLoader.getSystemClassLoader()方法调用。 ClassLoader 下所有的 getSystemXXX()的静态方法都是通过这个方法定义的。在代码中,应该尽量少地调用这个方法,以其它的类加载器作为代理。否则代码将只能工作在简单的命令行应用中。当在web应用中时,服务器也是利用ClassLoader来加载class的,由于ClassLoader的不同,所以在强制转型时JVM认定不是同一类型。(在JAVA中,一个类用其完全匹配类名(fully qualified class name)作为标识,这里指的完全匹配类名包括包名和类名。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此,如果一个名为Pg的包中,有一个名为Cl的类,被类加载器KlassLoader的一个实例kl1加载,Cl的实例,即C1.class在JVM中表示为(Cl, Pg, kl1)。这意味着两个类加载器的实例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的,被它们所加载的类也因此完全不同,互不兼容的。)为了能够使程序正确运行,我们首要解决的问题就是,如何将URLClassLoader加载的类,同当前ClassLoader保持在同一类加载器中。解决方法很简单,利用java提供的第三种ClassLoader—当前线程类加载器即可。jdk api文档就会发现,URLClassLoader提供了三种构造方式:

    // 使用默认的委托父 ClassLoader 为指定的 URL 构造一个新 URLClassLoader。
    URLClassLoader(URL[] urls)
    // 为给定的 URL 构造新 URLClassLoader。
    URLClassLoader(URL[] urls, ClassLoader parent)
    // 为指定的 URL、父类加载器和 URLStreamHandlerFactory 创建新 URLClassLoader。
    URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory)
    接下来要做的就是,在构造URLClassLoader时,将当前线程类加载器置入即可。如下:

    URLClassLoader myClassLoader =   new URLClassLoader( new URL[]   { url } , Thread.currentThread().getContextClassLoader());
    总结:
      Java是利用ClassLoader来加载类到内存的,ClassLoader本身是用java语言写的,所以我们可以扩展自己的ClassLoader。利用URLClassLoader可以加载指定jar包中的类到内存。在命行上利用URLClassLoader加载jar时,是使用系统类加载器来加载class的,所以在web环境下,就会出错。这是因为JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识的。我们只要利用URLClassLoader的第二种构造方法并传入当前线程类加载器即可解决。

    http://www.mxjava.com/blog/article.asp?id=188

    我的示例程序:

    import java.io.IOException;
    import java.io.PrintWriter;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import pk.Cs;

    import java.net.URL;
    import java.net.URLClassLoader;

    import Evaluated.PfInterface;

    public class a extends HttpServlet {

    /**
    * The doGet method of the servlet. <br>
    *
    * This method is called when a form has its tag value method equals to get.
    *
    * @param request the request send by the client to the server
    * @param response the response send by the server to the client
    * @throws ServletException if an error occurred
    * @throws IOException if an error occurred
    */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

       response.setContentType("text/html");
       PrintWriter out = response.getWriter();
      
      
      
      

       double []a={2,3};
        int []b={1,3};
        double f=5;
        int x=9;

       // 接口中方法的实现包
         //URL url = new URL("file:D:/eclipse/workspace/PfInterfaceFun.jar");
        URL url = new URL("file:D:/MyEclipse 5.5.1 GA/workspace/PfInterfaceFun.jar");
         //URLClassLoader myClassLoader = new URLClassLoader(new URL[] { url });  
        
         URLClassLoader myClassLoader =   new URLClassLoader( new URL[]   { url } , Thread.currentThread().getContextClassLoader());
       
          Class myClass=null;
        try {
         myClass = myClassLoader.loadClass("Evaluated.PfInterfaceFun");
        } catch (ClassNotFoundException e1) {
         // TODO Auto-generated catch block
         e1.printStackTrace();
        }
      
       
       PfInterface action=null;
        try {
         action = (PfInterface) myClass.newInstance();
        } catch (InstantiationException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        } catch (IllegalAccessException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }
       
       out.print(action.GetPF(a,b,f,f,f,f,f,f,x,x,f,x,x,x,x,x)+" --URLClassLoader result<br/>");//调用接口函数


      
      
      
      
      
       int i,j,k;
       Cs go = new Cs();

       i=123;
       out.print("The result is "+ go.fun(i)+"<br/>");

       out
         .println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
       out.println("<HTML>");
       out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
       out.println(" <BODY>");
       out.print("    This is ");
       out.print(this.getClass());
       out.println(", using the GET method");
       out.println(" </BODY>");
       out.println("</HTML>");
       out.flush();
       out.close();
    }
    }

  • 相关阅读:
    Grails入门教程(二)
    为脚本语言平反JavaScript篇(2)
    【CEO来信】李开复:创新工场我的新公司
    api测试常用测试点
    04 jmeter线程介绍及脚本编写
    02 改变jmeter工具GUI永久使用中文方法
    Mac配置hosts文件
    03 GUI界面的错误日志查看及清除
    页面存在多个url,使用jmeter进行遍历操作
    2.0数据之独立存储(Isolated Storage)
  • 原文地址:https://www.cnblogs.com/yesun/p/1498870.html
Copyright © 2011-2022 走看看