`

java中的类加载器,与tomcat自己又做了一些类加载器的不同

阅读更多

52.  现在来讲一下java中的类加载器的原理(双亲委派机制),在java中主要有三个加载器,启动类加载器,还有扩展类,还有系统类或者叫应用类加载器都行。不同的加载器啊,他找的东西不一样。


53.  那些核心啦,比如  java核心 java.开头那些,
那些api他都是BootStrap加载的。

54.  Ext扩展类加载器,他可以加载,你到java的安装目录下   jdk\jre\ext   这个目录下的东西都扩展类加载器加的,里面有dnsns.jar  localedate.jar  sunjce_provider.jar  sumkcs11.jar当然他的安装的是jdk1.5的。


55.  还有我们平时说的classpath,我们自己设置的classpath,就是把我们的类设置到classpath里面,把我们的jar包,加载到classpath里面,加载到classpath里面的东西是System加载器加载的。


56.  为什么加载器这样分了一些级呢?是这样的,java的加载,你看啊,在我们的核心库里面有一个String,这个String是用BootStrap加载器加载的。

现在假设我自己写的一个String和rt.jar里面的String是一模一样的。包括包名之类的,位于哪里呢?位于我们的classpath路径下,那么java的类加载器是这样加载的,他先请求他的父加载器,也就是说他先请求Ext加载器,看看他能不能加载,请示到这的时候,他还不能加载就再调用父加载器。你写的这个东西永远都加载不了,所以这样能起到一个安全性的作用,你破坏不了java虚拟机他的类加载机制,也就是你不能写一个String把java中的String给替了,因为他使用了一种机制叫   双亲委派机制。

想要加载一个东西的时候,他先委派他的双亲,往上面看,看看他能不能加,不能加再往上面看,除非你把java的api给改了。把他的jar包打开,改了再保存进去。

BootStrap

Ext

System

自定义加载器


57.  你不能像上面说的那样改啊,你这种权力都有了,那他的各种安全性就没有了。


58.  另外,你可以自己定义类加载器,你可以继承相关的类,自己定义一套加载策略,这个加载策略,你可以从url加载,就我给你一个url地址,然后你通过url把那个类从远程传过来加载,其实就像那个applet,其实这个现在用得比较少,在我们的ie里面可以嵌套applet.他这个我们可以看作是一种远程加载,因为applet呢,使用的话,你的本地是要有虚拟机的,虚拟机其实他就是一个url把远程的class加载过来,就你自己可以写加载器,我给你一个url你把class加载进来,加到你内存里来用。


59.  现在咱们写一个例子,看能不能覆盖java中的String  
包为  java.lang
public class String{
    public  int length(){
        int 100;
    }
}你在测试的时候
String s = new String();
System.out.println(s.length()); 打印0,说明调用的是java中的类,而非我自己写的类。


60.  之后我们再来看,tomcat加载机制就不太一样,这种web服务器,包括weblogic这种应用服务器,他们都有自己的类加载机制,就是把加载机制给扩展了,自己定义了一套加载机制,就像我们现在这个tomcat这个加载机制是这样的,

Bootstrap
Ext
System  前面肯定是java的类加载机制,然后下面    tomcat对java的类加载机制进行了扩展,
    Common  下面平行两个 catalina  shared
catalina  Shared
      Web App1  Web App2    shared下面是两个并行的Web App1  Web App2

意思就是drp6.3有6.3的类加载机制,drp6.2有6.2的加载器。


61.  所以在两个web项目里,我们可以用相同的类,他自己用自己的,不会冲突,


62.  上面的层次不就是tomcat的目录结构不,注意啦,如果实在找不出错误,可能同事在tomcat的公共目录里面放入了一个jar,而你自己的项目中也有jar ,可能会造成冲突。


63. 他说什么使用递归打印tomcat里面类加载器的层次,就像上面说的,从下往上打印类加载器


64.  写了一个DbUtil类,这个工程一运行,打印如下
WebappClassLoader
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@54172f

org.apache.catalina.loader.StandardClassLoader@54172f
sun.misc.Launcher$AppClassLoader@19821f
sun.misc.Launcher$ExtClassLoader@addbf1
null     最上层加载器



65.  工程名叫  test_webcalssloader,一运行,在控制台可以看到最后面的一个打印语句,打印一个null,其实应该指的就是最上面那个加载器,最上层的加载器是java的启动类加载器,这个加载器是加载java核心的,这个加载器不是用java实现的,他应该是用c++什么之类 的实现的,这个加载器没有名字,没有名字也有他一个好处,不至少于进行破坏,因为你不知道叫什么名字,很多人想要破坏java虚拟机,他就破坏不了,


66.  sun.misc.Launcher$ExtClassLoader@addbf1扩展类加载器用java实现的。
sun.misc.Launcher$AppClassLoader@19821f
对应上面的   System
org.apache.catalina.loader.StandardClassLoader@54172f对应上面的   Common

org.apache.catalina.loader.StandardClassLoader@54172f  对应上面的   Shared
再接下来的
WebappClassLoader
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@54172f
这个就对应我们的  webapp加载器了。


67.  上面列的tomcat的类加载器,其中common加载器主要就是加载   tomcat 下common目录下的东西,
shared加载器主要加载shared目录下的东西,
catalina加载器主要加载server目录下的东西,


68.  他这里搞一下,common目录下的classes目录下放一个文件夹下面放一个DbUtil2,share目录下的classes放一个文件夹下面放一个DbUtil
 
反正现在的情况就是
Common   DbUtil1
Shared   DbUtil2
Web App  DbUtil3
你说现在输出谁,肯定输出3,因为在Web App里面有他就会先加载3,这个他和java中的加载器他不一样,java是先加载自己的,比如上面写一个java.lang.String类没有用啊,他还是加载java的。

 

 

21.  类的加载机制,他采用了双亲委派机制,他为什么采用这种机制呢?安全性,java这里面他有String或者他的那些其他核心类,你想覆盖是覆盖不了的,因为你自己写的类他都属于classpath这个路径下,而classpath的加载器就是System即系统类加载器,你现在要使用String他首先会请求上面的加载器,你的永远加载不上。
bootstarp
ext
system
自定义加载


22.  在tomcat中的类加载器只不过是把自定义类加载器给扩充了。
bootstarp
ext
system
common     从这到最下面都 是自定义加载器
catalina  shared
web app1  web app2

23.  在tomcat里面有点不一样了,如果在webapp1里有一个test,在common里面也有一个test,一运行话,他先找自己的,如果web app1自己能加载,他就使用自己的来加载,这和java一上来就去找上面的加载器不一样了。

 

 

 

 

 

        今天看了张老师的类加载器的相关知识。说实在的,以前根本不了解类加载器的知识,所有看起来有的费劲。看完一遍视频还是对类加载器糊里糊涂的。因此有必要进行复习或者找资料学习相关知识。

       类加载器的第一个视频时类加载器及其委托机制的深入分析。

由张老师的讲解课知,Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader。类加载器也是一个Java类,因为其他是Java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap。Java虚拟机中的所有类转载器采用具有父子关系的树形结构进行组织,在实例化每个类转载器对象时,需要为其指定一个父级类转载器对象或者默认采用系统类转载器为其父级类加载。例如:如果我们想要看某个类加载他的类加载器及其父级类加载器,我们可以这样:

       定义一个类ClassLoaderTest,该类里面有一个main方法,如果我们要查看该类的类加载器的名称,我们可以这么做:

       System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());,运行结果为:sun.misc.Launcher$AppClassLoader,可见是AppClassLoader加载该类。如果需要查看加载系统类的类加载器,则:System.out.println(System.class.getClassLoader());结果为:null。如果要查看加载该类的类加载器以及其父级类加载器,则如下:

       ClassLoader loader = Test1.class.getClassLoader();

            while(loader != null) {

                  System.out.println(loader);

                  loader = loader.getParent();   

            }

该段代码为首选获取该类的类加载器,然后输出该类的类加载器并循环输出不为空的父级类加载器。结果为:sun.misc.Launcher$AppClassLoader@82ba41

sun.misc.Launcher$ExtClassLoader@923e30

每个类加载器都有自己对应的管辖范围。AppClassLoader对应得管辖范围是CLASSPATH指定的jar或目录,ExtClassLoader对应的管辖范围是JRE/lib/ext/*.jar,BootStrap对于的管辖范围是JRE/lib/rt.jar.这时我们就知道加载我们的测试类的类加载器为什么是AppClassLoader,因为AppClassLoader对应的管辖范围是CLASSPATH指定的jar或目录,而我们的类只在我们指定的CLASSPATH指定的目录存在,所以只能用AppClassLoader加载我们的类。那么如果ExtClassLoader对应的管辖范围存在我们的类即JRE/lib/ext目录下存在含有我们的测试类的jar,这时会是什么情况呢?我们将我们的测试类导出为jar到JRE/lib/ext目录下,再测试该类,得到了结果如下:

sun.misc.Launcher$ExtClassLoader@923e30

也就是加载该类的类加载器为ExtClassLoader,而其父级类加载器值为null。这也就验证了如果父级类加载器存在类时会优先加载。

以上就是类加载器及其委托机制的原理。

       既然了解了类加载器委托机制的原理,我们来编写一个自己的类加载器。要写我们自己的类加载器,我没写的类必须继承ClassLoader这个抽象类,然后实现findClass方法和defineClass方法。

在编写我们自己的类加载器前我们来编写个工具类来将java编译过的类进行加密,我们举一个简单的加密方法,就是将class文件的说有字节去反,我们编写一个方法来实现这个功能。我们定义一个方法copy,方法代码如下:

       private static void copy(InputStream is, OutputStream os)

throws Exception {

            int data = -1;

            while ((data = is.read()) != -1) {

                  os.write(data ^ 0XFF);      //取反操作

            }

       }

通过这个方法可以将class进行简单的加密操作。为了测试的方便,我们将类存在的目录硬编码。并定义存放加密后的class文件的存放的目录,然后根据文件输出流和文件输入流进行简单加密操作,具体代码如下:

public static void main(String[] args) throws Exception {

String in = "D:\\java\\mypro\\bin\\com\\base\\classloader\\ClassLoaderAttechment.class";   //加密前的class文件的路径

String out = "D:\\java\\mypro\\src\\myclass"; //加密后class存放的目录

String fileName = in.substring(in.lastIndexOf('\\')+1);

String toFile = out + "\\" + fileName;

FileInputStream fis = new FileInputStream(new File(in));

FileOutputStream fos = new FileOutputStream(new File(toFile));

copy(fis, fos);

fis.close();

fos.close();

}

运行后,在目录D:\\java\\mypro\\src\\myclass下就会生成加密后的class文件。此时class文件基本加密成功。

之后,我们开始写我们自己的类加载器的类。该类要继承ClassLoader类,并实现findClass这个方法。首先我们在类中定义一个私有属性:classDir,就是要加载的类的目录,并提供一个带参数的构造函数,以及getter和setter方法。然后提供一个解密方法,由于我们加密时只是将class文件的所有字节取反,所以解密的时候只需要将加密的class取反就行,因此还可以用到上面的copy方法。在findClass方法中,我们定义一个文件输入流来获取要加载的类的二进制数据,并定义一个字节数组输出流存放解密后的字节数据,并用defineClass方法将字节数组输出流生成类,另外如果在没加载到class时,我们还可以用父级的类加载器加载数据(如果父级类加载器的管辖范围存在测试类时)。findClass方法代码如下:

protected Class<?> findClass(String name) throws ClassNotFoundException {

            String file = this.getClassDir() + "\\" + name +".class";

            try {

                  FileInputStream fis = new FileInputStream(new File(file));

                  ByteArrayOutputStream abos = new ByteArrayOutputStream();

                  copy(fis , abos);

                  byte bytes [] =abos.toByteArray();

                  return this.defineClass(null, bytes, 0, bytes.length);

            } catch (Exception e) {

                  e.printStackTrace();

            }

            return super.findClass(name);

}

最后我们编写一个测试类:

public class ClassLoaderAttechment {

       @Override

       public String toString() {

            return "hello World";

       }

}

在测试类中调用自己的类加载器:

public static void main(String[] args) throws Exception {

Class clazz = new MyClassLoader("D:\\java\\mypro\\src\\myclass").findClass("ClassLoaderAttechment");

            Object d = (Object)clazz.newInstance();

            System.out.println(d);

}

需要注意的是此时实例化时应将实例化的对象强制转换为Object类,用类去应用。最后就能打印出:hello World。至此,我们的类加载器测试就成功了!

分享到:
评论

相关推荐

    java类加载器-tomcat中的类加载器

    下面我们将深入探讨Java类加载器以及Tomcat中的类加载器。 在Java中,类加载器主要分为三个层次:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader。Bootstrap ClassLoader负责加载JDK的核心库,如rt...

    tomcat类加载器

    类加载器在Tomcat中扮演着至关重要的角色,因为它们负责加载并管理运行时所需的Java类。这个"DevLoader.zip"文件可能包含与Tomcat自定义类加载器相关的资料,特别是名为"DevLoader"的类加载器,这可能是Tomcat为...

    类加载器与Tomcat

    Tomcat的类加载器设计遵循了Java的双亲委派模型,但又在其基础上进行了一些定制,以满足Web应用程序的特定需求。 首先,Tomcat的类加载器层次结构由Bootstrap类加载器、Common类加载器、Shared类加载器和Web应用...

    类加载器(java)

    Java中的类加载器是JVM(Java虚拟机)的核心组件之一,它们负责将.java源代码编译成的.class字节码文件加载到JVM中,从而使得程序能够运行。类加载器不仅涉及到程序的正常执行,还与Java的动态加载、模块化系统以及...

    Java 类在 Tomcat 中是如何加载的(过程分析)

    - **多应用共享jar包**:如果多个应用程序使用相同的jar包,而每个应用都有自己的类加载器,可能会因为类加载器的不同而导致类加载问题。 理解这些知识点有助于开发者更好地管理Tomcat中的类加载,避免潜在的问题...

    tomcat 类加载机制 —— ClassLoader

    在Tomcat中,我们可以通过配置`catalina.properties`文件和`server.xml`文件来调整类加载策略,例如设置自定义的类加载顺序或启用共享类加载器。 此外,Tomcat还支持热部署,即在不重启服务器的情况下更新Web应用的...

    深入探讨 Java 类加载器

    在Web容器(如Tomcat)中,每个Web应用都有自己的类加载器,这样可以确保不同应用的类之间隔离,避免冲突。而在OSGi环境下,类加载器被用来实现模块间的隔离,每个模块(Bundle)都拥有自己的类加载器,实现了更细...

    JVM、Tomcat、OSGI等类加载器整理文档

    在Java世界中,类加载器(ClassLoader)是关键组件,它们负责将类的字节码加载到Java虚拟机(JVM)中。JVM、OSGI(Open Service Gateway Initiative)和Tomcat等容器都涉及到了类加载器的概念,理解它们的工作原理对...

    深入探讨 Java 类加载器.pdf

    - **Web容器**:现代Web容器(如Tomcat、Jetty等)广泛使用类加载器来支持多应用共存环境下的隔离性,每个Web应用都有自己的类加载器,这样可以避免不同应用之间的类冲突问题。 - **OSGi**:OSGi是一个Java平台的...

    Tomcat启动时类加载顺序

    Tomcat通过自定义的类加载器实现了特定的类加载顺序,以确保能够正确处理不同来源的类文件,避免类的重复加载和类版本冲突问题。以下是Tomcat启动过程中类加载的具体顺序: #### 三、类加载顺序详述 1. **Bootstrap...

    apache-tomcat-8.5.87-src 类加载器WebappClassLoaderBase修改,web项目加密解密

    在Java中,类加载器是根据双亲委托模型工作的,即当一个类加载器收到加载类的请求时,它会先委托给父类加载器,只有当父类加载器无法找到对应的类时,才会尝试自己加载。在Tomcat中,WebappClassLoaderBase的父类...

    java 反射运行时加载外部jar到Tomcat StandardClassLoader1

    在这个例子中,使用 `getClass().getClassLoader()` 获取到当前页面的类加载器,然后通过 `getParent().getParent()` 得到 `StandardClassLoader`,因为它位于应用程序类加载器的父加载器中。 ```java ...

    java利用ManagementFactory获取tomcat的一些信息例子

    在Java编程语言中,我们可以利用Java管理扩展(Java Management Extensions, JMX)和ManagementFactory类来获取应用程序,如Tomcat服务器的运行时信息。本文将深入探讨如何通过这些工具来监控Tomcat的一些关键信息。...

    java 类加载与自定义类加载器详解

    Java中的类加载器通常分为三种:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader)。它们遵循双亲委派模型,即较低层次的类加载器会将...

    译 Java类加载机制(二)

    在Java中,主要有三种类型的类加载器:bootstrap classloader(引导类加载器)、extension classloader(扩展类加载器)和app classloader(应用类加载器)。Bootstrap ClassLoader负责加载JRE核心库,Extension ...

    Tomcat启动顺序

    每个Web应用都有自己的WebApp类加载器,负责加载该应用的`WEB-INF/classes`和`WEB-INF/lib`目录下的类和资源。这种隔离设计确保了不同Web应用程序之间的类库独立性,避免了类冲突问题。 在启动过程中,Tomcat还会...

    tomcat 部署java项目 jar

    标题中的“tomcat部署java项目jar”指的是在Apache Tomcat服务器上部署Java Web应用程序,通常以JAR(Java Archive)格式打包。Tomcat是一个开源的轻量级应用服务器,主要用于运行Servlet和JSP(JavaServer Pages)...

    Java类加载

    在一些特定的应用场景下,如 Tomcat 服务器,会使用更为复杂的类加载器架构。例如,Tomcat 使用了多种类加载器来处理不同的类资源: 1. **CommonClassLoader**: - 负责加载 `/common/*` 目录中的类。 2. **...

    Tomcat加载顺序

    这是JVM自带的类加载器,用于加载核心的类库,如`java.lang`、`java.util`等,这些类库存储在`$JAVA_HOME/jre/lib`目录下。Bootstrap ClassLoader不会从磁盘上加载任何类,而是直接读取JRE中的这些核心类库。 #### ...

    Tomcat 类加载器的实现方法及实例代码

    Tomcat 类加载器的实现主要围绕着Java的类加载机制进行,旨在确保应用之间的类隔离,并提供灵活的资源访问策略。下面我们将深入探讨这些知识点。 首先,Java的类加载机制是基于“双亲委托模型”的。当一个类加载器...

Global site tag (gtag.js) - Google Analytics