classLoader,从名字就可以知道,用于加载class的东西。

我们知道在Java中,源文件是会被编译成class文件的,我们的程序的运行也是需要依赖这些编译成字节码的class文件,而这些字节码文件就必须要被classLoader加载到内存之后才能使用。。。如果classLoader无法加载到我们要用的类型的class文件,那么将会抛出classnodfound的异常。。。

先用一张图来整体描述一下java标准中定义的classLoader的层次吧:

在整个定义中,一共有两种类型的加载器:

(1)启动类加载器:Bootstrap ClassLoader,这个类加载器是使用c++语言实现的,它本身就是虚拟机的一部分

(2)其他的类加载器,这些类加载器都是用java语言实现的,独立于虚拟机外部,并且他们都继承自抽象类java.lang.ClassLoader

另外按照功能来分的话可以如下:

(1)启动类加载器,也就是Bootstrap ClassLoader,这个类加载器负责将存放在<JAVA_HOME>/lib目录中的类库加载到虚拟机的内存中,而且它还要识别名字,如果名字不符合,就算放在lib目录中,也不会被加载,这个加载器无法被 java程序所引用。。。

(2)扩展类加载器,Extension ClassLoader,这个加载器负责加载<JAVA_HOME>/lib/ext目录中的类库,也就是扩展类库,java程序中可以直接引用这个加载器。。。。

(3)应用程序加载器,Application ClassLoader,它用与负责加载用户类路径上的类库,java程序中可以直接使用这个加载器,而且如果在应用程序中没有自定义过自己的类加载器,那么一般情况下这个就是程序中的默认加载器。。。。也就是loadClass啥的默认都是它了。。。。

另外从上面的图形也可以看成一种层次关系,除了最顶层的启动类加载器之外,其余的加载器都必须要有自己的父加载器(这个是组合实现的,不是继承)。。

这个也就是java中定义的所谓的双亲委派模型:

如果一个类加载器收到了 类加载的请求,那么它首先不会自己去尝试加载这个类,而是将这个请求委派给自己的父加载器去完成,每一层的加载器都是,因此任何一个加载请求都会自动传送到顶层的启动类加载器中,只有当自己的父加载器反馈无法完成这个加载请求的时候,子加载器才会去尝试自己去加载。。。。

这个是一个非常重要的定义,因为它限定了java在api方面的统一,越基础的类那么就由越基础的加载器来加载。。。。

(补充:同一个class文件,如果被不同的加载器加载,那么他们将会不相等)

这种双亲委派模型是java中默认以及推荐的模型,我们一般自己实现classLoader的时候也需要遵守这种规范,但是在web容器中就需要打破这种双亲委派模型了。。。

主流的Javaweb服务器,如tomcat,jetty,weblogic,啥的都有自己定义自己的类加载器。。。

因为在同一个服务器上我们会部署多个web应用程序,那么就需要这些web应用程序代码之间实现相互的隔离,而且web程序的类库还需要与服务器之间隔离,这样web应用程序的部署才不会影响到web服务器。。。

那么在这里就需要打破双亲委派的模型了。。。而且这里会用到线程上下文类加载器。。。(Thread context classLoader)

上面说了这么多,都是对java的classLoader的方面知识的一些普及,因为其实自己在之前也对这方面的概念都了解很少。。。

那么接下来就可开始来分析jetty中定义的WebAppClassLoader了,它在jetty中用于负责加载web应用程序WEB-INF目录下lib以及classes里面的类库。。说白了就是用于加载web应用程序自己的源代码。。。

先来看看它定义的一些比较重要的属性吧:

[java] view plaincopy

 
 
  1. private String _name;   //名字
  2. private WebAppContext _context;   //其所关联的webcontext
  3. private ClassLoader _parent;   //父classLoader

最开始的是当前loader名字,不知道为啥要有这个名字,感觉也没啥用....第二个参数就是当前classLoader所属的webcontext,这个属性就属于比较重要的了,,...。。。每一个web应用程序都会有一个属于自己的classlaoder,最后一个参数就是前面提到过的父classLoader,仿佛这里看起来是要用于实现上面说过的双亲委派,其实不然。。。

在我们自己定义的web应用程序中,一会用到其余的class代码,例如String,hashmap啥的,那么这里有一个parent,就可以保证可以在parent里面获取他们的class。。。。

那么接下来来看看它的构造函数吧:

[java] view plaincopy

 
 
  1. public WebAppClassLoader(WebAppContext context)
  2. throws IOException  {
  3. this(null,context);
  4. }
  5. /* ------------------------------------------------------------ */
  6. /** Constructor.
  7. */
  8. //这里可以看出,如果在构建的时候没有提供父亲classLoader,那么将会默认将当前的线程classLoader作为当前的父classLoader
  9. public WebAppClassLoader(ClassLoader parent, WebAppContext context)
  10. throws IOException {
  11. super(new URL[]{},parent!=null?parent
  12. :(Thread.currentThread().getContextClassLoader()!=null?Thread.currentThread().getContextClassLoader()
  13. :(WebAppClassLoader.class.getClassLoader()!=null?WebAppClassLoader.class.getClassLoader()
  14. :ClassLoader.getSystemClassLoader())));
  15. _parent=getParent();  //指向当前的parent
  16. _context=context;  //保存当前的context
  17. if (_parent==null)
  18. throw new IllegalArgumentException("no parent classloader!");
  19. if (context.getExtraClasspath()!=null) {
  20. addClassPath(context.getExtraClasspath());
  21. }
  22. }

其实这里一般情况下都是会调用第一个构造函数,第二个构造函数主要是要满足父类URLClassLoader的构造,它是java系统类库中的。。。而且到这里就能够知道其实这里默认是将当前的线程上下文classLoader指定为当前的parent,而这个线程上下文classLoader如果没有用户指定的话默认又将是前面提到过的appClassLoader,也就是用于加载用户代码的classLoader。。。。

接下来来看看它定义的loadClass方法吧:

[java] view plaincopy

 
 
  1. //加载类,因为每一个webContext 都会有一个自己的classLoader,所以也就是先了web应用程序代码之间的相互隔离
  2. protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
  3. Class c= findLoadedClass(name);  //首先在自己这里加载,我们自己定义的代码,引用的jar里面的代码都是在这里加载的
  4. ClassNotFoundException ex= null;
  5. boolean tried_parent= false;
  6. //如果父类加载器优先,或者这里加载的类型是系统类型,例如"java.","javax.servlet.","javax.xml.",那么由父类加载器来加载
  7. //不过webapp的代码父类加载器肯定是加载不倒的
  8. if (c == null && _parent!=null && (_context.isParentLoaderPriority() || isSystemPath(name)) ) {
  9. tried_parent= true;
  10. try {
  11. //这里的parent就是appclassLoader
  12. c= _parent.loadClass(name);  //由父类加载,一些系统代码,例如hashMap,set啥的都在这里加载,还有jetty定义的也在这里加载,例如org.mortbay.servlet.NoJspServlet
  13. if (Log.isDebugEnabled())
  14. Log.debug("loaded " + c);
  15. }  catch (ClassNotFoundException e) {
  16. ex= e;
  17. }
  18. }
  19. if (c == null) {
  20. try  {
  21. c= this.findClass(name);  //这里是从当前classLoader的路径下面去加载
  22. } catch (ClassNotFoundException e) {
  23. ex= e;
  24. }
  25. }
  26. if (c == null && _parent!=null && !tried_parent && !isServerPath(name) )
  27. c= _parent.loadClass(name);
  28. if (c == null)
  29. throw ex;
  30. if (resolve)
  31. resolveClass(c);
  32. if (Log.isDebugEnabled())
  33. Log.debug("loaded " + c+ " from "+c.getClassLoader());
  34. return c;
  35. }

这段代码其实还算是比较的简单吧。。。这里就可以知道指定parent的重要作用了。。。因为毕竟在我们自己的代码中也会有调用一些类库中的代码。。。而在parent中,却无法加载到我们自己定义的class文件。。。也就实现代码与jetty 服务器本身的隔离。。。。

又因为每一个web应用程序都有自己的classLoader,也就是先了在同一个服务器下,不同的app之间的代码隔离。。。

最后再来补充两个方法吧:

[java] view plaincopy

 
 
  1. //添加class或者jar的路径,如果是文件夹路径的话,那么路径应该以/  结尾
  2. public void addClassPath(String classPath)
  3. throws IOException {
  4. if (classPath == null)
  5. return;
  6. StringTokenizer tokenizer= new StringTokenizer(classPath, ",;");  //有可能一次性传入多个classLoader
  7. while (tokenizer.hasMoreTokens()) {
  8. /*
  9. * file:/C:/Users/js/AppData/Local/Temp/Jetty_127_0_0_1_80_manager.war__manager__.24ly2g/webapp/WEB-INF/classes/
  10. file:/C:/Users/js/AppData/Local/Temp/Jetty_127_0_0_1_80_manager.war__manager__.24ly2g/webapp/WEB-INF/lib/aopalliance-1.0.jar
  11. file:/C:/Users/js/AppData/Local/Temp/Jetty_127_0_0_1_80_manager.war__manager__.24ly2g/webapp/WEB-INF/lib/commons-collections-3.1.jar
  12. */
  13. Resource resource= Resource.newResource(tokenizer.nextToken());  //获取当前路径的resource对象
  14. if (Log.isDebugEnabled())
  15. Log.debug("Path resource=" + resource);
  16. // Resolve file path if possible
  17. File file= resource.getFile();  //获取当前的文件
  18. if (file != null) {
  19. URL url= resource.getURL();  //获取url
  20. addURL(url);   //这个是父类的方法,将会加载这个路径下的class或者jar资源
  21. } else {
  22. // Add resource or expand jar/
  23. if (!resource.isDirectory() && file == null)
  24. {
  25. InputStream in= resource.getInputStream();
  26. File tmp_dir=_context.getTempDirectory();
  27. if (tmp_dir==null)
  28. {
  29. tmp_dir = File.createTempFile("jetty.cl.lib",null);
  30. tmp_dir.mkdir();
  31. tmp_dir.deleteOnExit();
  32. }
  33. File lib= new File(tmp_dir, "lib");
  34. if (!lib.exists())
  35. {
  36. lib.mkdir();
  37. lib.deleteOnExit();
  38. }
  39. File jar= File.createTempFile("Jetty-", ".jar", lib);
  40. jar.deleteOnExit();
  41. if (Log.isDebugEnabled())
  42. Log.debug("Extract " + resource + " to " + jar);
  43. FileOutputStream out = null;
  44. try
  45. {
  46. out= new FileOutputStream(jar);
  47. IO.copy(in, out);
  48. }
  49. finally
  50. {
  51. IO.close(out);
  52. }
  53. URL url= jar.toURL();
  54. addURL(url);
  55. } else {
  56. URL url= resource.getURL();
  57. addURL(url);  //添加class的搜索路径
  58. }
  59. }
  60. }
  61. }
  62. //添加jar包或压缩文件
  63. public void addJars(Resource lib)  {
  64. if (lib.exists() && lib.isDirectory())
  65. {
  66. String[] files=lib.list();  //获取当前文件夹下面的所有文件
  67. //遍历下面的所有文件
  68. for (int f=0;files!=null && f<files.length;f++)  {
  69. try {
  70. Resource fn=lib.addPath(files[f]);    //获取这个文件的resource
  71. String fnlc=fn.getName().toLowerCase();
  72. //判断文件的扩展名是否正确
  73. if (fnlc.endsWith(".jar") || fnlc.endsWith(".zip"))  {
  74. String jar=fn.toString();
  75. jar=StringUtil.replace(jar, ",", "%2C");
  76. jar=StringUtil.replace(jar, ";", "%3B");
  77. addClassPath(jar); //调用addClassPath来将jar包加载
  78. }
  79. }  catch (Exception ex) {
  80. Log.warn(Log.EXCEPTION,ex);
  81. }
  82. }
  83. }
  84. }

这两个方法的定义应该从名字就能够知道是干嘛的。。用于加载jar包或者class文件的。。最终是通过父类的addUrl的方法来实现这些源文件的加载。。。

好了,到这里jetty中定义的webappclassLoader就算是比较清楚了。。不过比较遗憾没有去分析它的父类URLClassLoader,从而对java的整个classLoader有更深的了解。。以后有机会的话看看吧。。

这样子就可以开始看jetty中如何创建webContext以及启动这些web应用程序了。。。

classLoader,从名字就可以知道,用于加载class的东西。

我们知道在Java中,源文件是会被编译成class文件的,我们的程序的运行也是需要依赖这些编译成字节码的class文件,而这些字节码文件就必须要被classLoader加载到内存之后才能使用。。。如果classLoader无法加载到我们要用的类型的class文件,那么将会抛出classnodfound的异常。。。

先用一张图来整体描述一下java标准中定义的classLoader的层次吧:

在整个定义中,一共有两种类型的加载器:

(1)启动类加载器:Bootstrap ClassLoader,这个类加载器是使用c++语言实现的,它本身就是虚拟机的一部分

(2)其他的类加载器,这些类加载器都是用java语言实现的,独立于虚拟机外部,并且他们都继承自抽象类java.lang.ClassLoader

另外按照功能来分的话可以如下:

(1)启动类加载器,也就是Bootstrap ClassLoader,这个类加载器负责将存放在<JAVA_HOME>/lib目录中的类库加载到虚拟机的内存中,而且它还要识别名字,如果名字不符合,就算放在lib目录中,也不会被加载,这个加载器无法被 java程序所引用。。。

(2)扩展类加载器,Extension ClassLoader,这个加载器负责加载<JAVA_HOME>/lib/ext目录中的类库,也就是扩展类库,java程序中可以直接引用这个加载器。。。。

(3)应用程序加载器,Application ClassLoader,它用与负责加载用户类路径上的类库,java程序中可以直接使用这个加载器,而且如果在应用程序中没有自定义过自己的类加载器,那么一般情况下这个就是程序中的默认加载器。。。。也就是loadClass啥的默认都是它了。。。。

另外从上面的图形也可以看成一种层次关系,除了最顶层的启动类加载器之外,其余的加载器都必须要有自己的父加载器(这个是组合实现的,不是继承)。。

这个也就是java中定义的所谓的双亲委派模型:

如果一个类加载器收到了 类加载的请求,那么它首先不会自己去尝试加载这个类,而是将这个请求委派给自己的父加载器去完成,每一层的加载器都是,因此任何一个加载请求都会自动传送到顶层的启动类加载器中,只有当自己的父加载器反馈无法完成这个加载请求的时候,子加载器才会去尝试自己去加载。。。。

这个是一个非常重要的定义,因为它限定了java在api方面的统一,越基础的类那么就由越基础的加载器来加载。。。。

(补充:同一个class文件,如果被不同的加载器加载,那么他们将会不相等)

这种双亲委派模型是java中默认以及推荐的模型,我们一般自己实现classLoader的时候也需要遵守这种规范,但是在web容器中就需要打破这种双亲委派模型了。。。

主流的Javaweb服务器,如tomcat,jetty,weblogic,啥的都有自己定义自己的类加载器。。。

因为在同一个服务器上我们会部署多个web应用程序,那么就需要这些web应用程序代码之间实现相互的隔离,而且web程序的类库还需要与服务器之间隔离,这样web应用程序的部署才不会影响到web服务器。。。

那么在这里就需要打破双亲委派的模型了。。。而且这里会用到线程上下文类加载器。。。(Thread context classLoader)

上面说了这么多,都是对java的classLoader的方面知识的一些普及,因为其实自己在之前也对这方面的概念都了解很少。。。

那么接下来就可开始来分析jetty中定义的WebAppClassLoader了,它在jetty中用于负责加载web应用程序WEB-INF目录下lib以及classes里面的类库。。说白了就是用于加载web应用程序自己的源代码。。。

先来看看它定义的一些比较重要的属性吧:

[java] view plaincopy

 
 
  1. private String _name;   //名字
  2. private WebAppContext _context;   //其所关联的webcontext
  3. private ClassLoader _parent;   //父classLoader

最开始的是当前loader名字,不知道为啥要有这个名字,感觉也没啥用....第二个参数就是当前classLoader所属的webcontext,这个属性就属于比较重要的了,,...。。。每一个web应用程序都会有一个属于自己的classlaoder,最后一个参数就是前面提到过的父classLoader,仿佛这里看起来是要用于实现上面说过的双亲委派,其实不然。。。

在我们自己定义的web应用程序中,一会用到其余的class代码,例如String,hashmap啥的,那么这里有一个parent,就可以保证可以在parent里面获取他们的class。。。。

那么接下来来看看它的构造函数吧:

[java] view plaincopy

 
 
  1. public WebAppClassLoader(WebAppContext context)
  2. throws IOException  {
  3. this(null,context);
  4. }
  5. /* ------------------------------------------------------------ */
  6. /** Constructor.
  7. */
  8. //这里可以看出,如果在构建的时候没有提供父亲classLoader,那么将会默认将当前的线程classLoader作为当前的父classLoader
  9. public WebAppClassLoader(ClassLoader parent, WebAppContext context)
  10. throws IOException {
  11. super(new URL[]{},parent!=null?parent
  12. :(Thread.currentThread().getContextClassLoader()!=null?Thread.currentThread().getContextClassLoader()
  13. :(WebAppClassLoader.class.getClassLoader()!=null?WebAppClassLoader.class.getClassLoader()
  14. :ClassLoader.getSystemClassLoader())));
  15. _parent=getParent();  //指向当前的parent
  16. _context=context;  //保存当前的context
  17. if (_parent==null)
  18. throw new IllegalArgumentException("no parent classloader!");
  19. if (context.getExtraClasspath()!=null) {
  20. addClassPath(context.getExtraClasspath());
  21. }
  22. }

其实这里一般情况下都是会调用第一个构造函数,第二个构造函数主要是要满足父类URLClassLoader的构造,它是java系统类库中的。。。而且到这里就能够知道其实这里默认是将当前的线程上下文classLoader指定为当前的parent,而这个线程上下文classLoader如果没有用户指定的话默认又将是前面提到过的appClassLoader,也就是用于加载用户代码的classLoader。。。。

接下来来看看它定义的loadClass方法吧:

[java] view plaincopy

 
 
  1. //加载类,因为每一个webContext 都会有一个自己的classLoader,所以也就是先了web应用程序代码之间的相互隔离
  2. protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
  3. Class c= findLoadedClass(name);  //首先在自己这里加载,我们自己定义的代码,引用的jar里面的代码都是在这里加载的
  4. ClassNotFoundException ex= null;
  5. boolean tried_parent= false;
  6. //如果父类加载器优先,或者这里加载的类型是系统类型,例如"java.","javax.servlet.","javax.xml.",那么由父类加载器来加载
  7. //不过webapp的代码父类加载器肯定是加载不倒的
  8. if (c == null && _parent!=null && (_context.isParentLoaderPriority() || isSystemPath(name)) ) {
  9. tried_parent= true;
  10. try {
  11. //这里的parent就是appclassLoader
  12. c= _parent.loadClass(name);  //由父类加载,一些系统代码,例如hashMap,set啥的都在这里加载,还有jetty定义的也在这里加载,例如org.mortbay.servlet.NoJspServlet
  13. if (Log.isDebugEnabled())
  14. Log.debug("loaded " + c);
  15. }  catch (ClassNotFoundException e) {
  16. ex= e;
  17. }
  18. }
  19. if (c == null) {
  20. try  {
  21. c= this.findClass(name);  //这里是从当前classLoader的路径下面去加载
  22. } catch (ClassNotFoundException e) {
  23. ex= e;
  24. }
  25. }
  26. if (c == null && _parent!=null && !tried_parent && !isServerPath(name) )
  27. c= _parent.loadClass(name);
  28. if (c == null)
  29. throw ex;
  30. if (resolve)
  31. resolveClass(c);
  32. if (Log.isDebugEnabled())
  33. Log.debug("loaded " + c+ " from "+c.getClassLoader());
  34. return c;
  35. }

这段代码其实还算是比较的简单吧。。。这里就可以知道指定parent的重要作用了。。。因为毕竟在我们自己的代码中也会有调用一些类库中的代码。。。而在parent中,却无法加载到我们自己定义的class文件。。。也就实现代码与jetty 服务器本身的隔离。。。。

又因为每一个web应用程序都有自己的classLoader,也就是先了在同一个服务器下,不同的app之间的代码隔离。。。

最后再来补充两个方法吧:

[java] view plaincopy

 
 
  1. //添加class或者jar的路径,如果是文件夹路径的话,那么路径应该以/  结尾
  2. public void addClassPath(String classPath)
  3. throws IOException {
  4. if (classPath == null)
  5. return;
  6. StringTokenizer tokenizer= new StringTokenizer(classPath, ",;");  //有可能一次性传入多个classLoader
  7. while (tokenizer.hasMoreTokens()) {
  8. /*
  9. * file:/C:/Users/js/AppData/Local/Temp/Jetty_127_0_0_1_80_manager.war__manager__.24ly2g/webapp/WEB-INF/classes/
  10. file:/C:/Users/js/AppData/Local/Temp/Jetty_127_0_0_1_80_manager.war__manager__.24ly2g/webapp/WEB-INF/lib/aopalliance-1.0.jar
  11. file:/C:/Users/js/AppData/Local/Temp/Jetty_127_0_0_1_80_manager.war__manager__.24ly2g/webapp/WEB-INF/lib/commons-collections-3.1.jar
  12. */
  13. Resource resource= Resource.newResource(tokenizer.nextToken());  //获取当前路径的resource对象
  14. if (Log.isDebugEnabled())
  15. Log.debug("Path resource=" + resource);
  16. // Resolve file path if possible
  17. File file= resource.getFile();  //获取当前的文件
  18. if (file != null) {
  19. URL url= resource.getURL();  //获取url
  20. addURL(url);   //这个是父类的方法,将会加载这个路径下的class或者jar资源
  21. } else {
  22. // Add resource or expand jar/
  23. if (!resource.isDirectory() && file == null)
  24. {
  25. InputStream in= resource.getInputStream();
  26. File tmp_dir=_context.getTempDirectory();
  27. if (tmp_dir==null)
  28. {
  29. tmp_dir = File.createTempFile("jetty.cl.lib",null);
  30. tmp_dir.mkdir();
  31. tmp_dir.deleteOnExit();
  32. }
  33. File lib= new File(tmp_dir, "lib");
  34. if (!lib.exists())
  35. {
  36. lib.mkdir();
  37. lib.deleteOnExit();
  38. }
  39. File jar= File.createTempFile("Jetty-", ".jar", lib);
  40. jar.deleteOnExit();
  41. if (Log.isDebugEnabled())
  42. Log.debug("Extract " + resource + " to " + jar);
  43. FileOutputStream out = null;
  44. try
  45. {
  46. out= new FileOutputStream(jar);
  47. IO.copy(in, out);
  48. }
  49. finally
  50. {
  51. IO.close(out);
  52. }
  53. URL url= jar.toURL();
  54. addURL(url);
  55. } else {
  56. URL url= resource.getURL();
  57. addURL(url);  //添加class的搜索路径
  58. }
  59. }
  60. }
  61. }
  62. //添加jar包或压缩文件
  63. public void addJars(Resource lib)  {
  64. if (lib.exists() && lib.isDirectory())
  65. {
  66. String[] files=lib.list();  //获取当前文件夹下面的所有文件
  67. //遍历下面的所有文件
  68. for (int f=0;files!=null && f<files.length;f++)  {
  69. try {
  70. Resource fn=lib.addPath(files[f]);    //获取这个文件的resource
  71. String fnlc=fn.getName().toLowerCase();
  72. //判断文件的扩展名是否正确
  73. if (fnlc.endsWith(".jar") || fnlc.endsWith(".zip"))  {
  74. String jar=fn.toString();
  75. jar=StringUtil.replace(jar, ",", "%2C");
  76. jar=StringUtil.replace(jar, ";", "%3B");
  77. addClassPath(jar); //调用addClassPath来将jar包加载
  78. }
  79. }  catch (Exception ex) {
  80. Log.warn(Log.EXCEPTION,ex);
  81. }
  82. }
  83. }
  84. }

这两个方法的定义应该从名字就能够知道是干嘛的。。用于加载jar包或者class文件的。。最终是通过父类的addUrl的方法来实现这些源文件的加载。。。

好了,到这里jetty中定义的webappclassLoader就算是比较清楚了。。不过比较遗憾没有去分析它的父类URLClassLoader,从而对java的整个classLoader有更深的了解。。以后有机会的话看看吧。。

这样子就可以开始看jetty中如何创建webContext以及启动这些web应用程序了。。。

java的classLoader分析与jettty的WebAppClassLoader的更多相关文章

  1. 【JVM】深度分析Java的ClassLoader机制(源码级别)

    原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...

  2. java的classLoader原理理解和分析

    java的classLoader原理理解和分析 学习了:http://blog.csdn.net/tangkund3218/article/details/50088249 ClassNotFound ...

  3. [Java类加载器]Java中classLoader浅析.

    本文为在公司内部TD上写的一篇小文, 主要讲解java中classLoader基础知识, 现在拿来这里分享一下. 一.问题 请在Eclipse中新建如下类,并运行它: 1 package java.l ...

  4. 常用 Java 静态代码分析工具的分析与比较

    常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...

  5. Java线程问题分析定位

    Java线程问题分析定位 分析步骤: 1.使用top命令查看系统资源占用情况,发现Java进程占用大量CPU资源,PID为11572: 2.显示进程详细列表命令:ps -mp 11572 -o THR ...

  6. java内存溢出分析(二)

    我们继续java内存溢出分析(一)的分析,点击Details>按钮,显示如下图,我们发现有一个对象数量达到280370216个,再点击其中的List objects 点击后,显示下图 至此,我们 ...

  7. 性能分析之-- JAVA Thread Dump 分析综述

    性能分析之-- JAVA Thread Dump 分析综述       一.Thread Dump介绍 1.1什么是Thread Dump? Thread Dump是非常有用的诊断Java应用问题的工 ...

  8. java初学的分析

    java初学的分析第一阶段:入门阶段学习目标:简单项目开发学习内容:1.Java入门书籍,Java基础知识.关于Java入门级的书,给大家推荐过<Java编程思想>.<Java核心技 ...

  9. Java基础—ClassLoader的理解

    ##默认的三个类加载器 Java默认是有三个ClassLoader,按层次关系从上到下依次是: - Bootstrap ClassLoader - Ext ClassLoader - System C ...

随机推荐

  1. 第84讲:Scala中List和ListBuffer设计实现思考

    今天来学习了scala中的list和ListBuffer scala list 内部很多操作是listbuffer做的,因为改变元素,listbuffer非常高效,tl是var类型的  ,但是他属于s ...

  2. hdu 4542 打表+含k个约数最小数

    http://acm.hdu.edu.cn/showproblem.php?pid=4542 给出一个数K和两个操作 如果操作是0,就求出一个最小的正整数X,满足X的约数个数为K. 如果操作是1,就求 ...

  3. Excel函数vlookup

    最近整理业务文档,需要用到excel,按照教程,操作了20来分钟,却得不到结果. 看了视频,才知道,vlookup仅限关联选中区域的第一列关联,把要关联的行拷贝到第一列,解决. https://www ...

  4. Android-Kotlin-抽象类与多态的表现

    选择包名,然后右键: 选择Class类型,会有class:  选择File类型,不会自动有class: 目录结构: 定义描述抽象类 Person人类: package cn.kotlin.kotlin ...

  5. Matlab中函数句柄@的作用及介绍

    问:f=@(x)acos(x)表示什么意思?其中@代表什么?答:表示f为函数句柄,@是定义句柄的运算符.f=@(x)acos(x) 相当于建立了一个函数文件:% f.mfunction  y=f(x) ...

  6. SharePoint 列表中增加列编辑功能菜单

    需求描述 在企业的部署中,经常将SharePoint和TFS集成在一起,两个系统之间相互读取数据,展现开发进度.在TFS 2018之前版本中,由于TFS的门户定制功能有限,用户比较喜欢使用ShareP ...

  7. jQuery的addClass,removeClass和toggleClass方法

    jQuery的addClass,removeClass和toggleClass方法,最后一个方法在某一情形之下,可以替代前面2个方法. 第一个方法addClass为元素添加一个class. 第二个方法 ...

  8. Class和普通js构造函数的区别

    Class 在语法上更加贴合面向对象的写法 Class 实现继承更加易读.易理解 更易于写 java 等后端语言的使用 本质还是语法糖,使用 prototype Class语法 typeof Math ...

  9. win10安装Ubuntu双系统

    1.软碟通做启动盘,不要用easyBCD,比较麻烦 2.windows10中取消选择"启用快速启动(推荐)" 3.压缩出空白卷 4.重启时按F12 5.在bios中将boot pr ...

  10. centoos 安装hadoop集群

    环境准备 两台centoos系统服务器 H30(192.168.3.238) H31(192.168.3.237) H30为master,H31为slave,slave后续还可以再加机器: 先通过xs ...