zoukankan      html  css  js  c++  java
  • 类加载机制,双亲委派的那些事

      首先我们来看张图,自己就不画了,网上找了张图。

       (内存模型就先不看了,1。8之后已经不是这个模型了)

      我们java的程序在加载到jvm之前,经历过的事情上面在类加载器之前我就不解释了,在.class文件到类加载器之间,还有一些过程。看下图

       加载:io读取磁盘上面的字节码文件,在对象被使用到的时候加载到内存

      验证:验证内存中读取字节码文件内容是否正确(里面是很多0-9和字母组成,class文件不要随意去更改)

      准备:这个阶段给静态成员分配地址,给默认值(基本类型都有默认值,如果成员中有对象的话,此时为null,即使是你代码中new了)

      解析:符号(类名,方法名,包名)这个静态链接过程怎么去解释呢,(这个理解了往后补充)

      初始化:把静态变量赋值为我们给的值

      我们再看类加载器:

        1:启动类加载器:加载jre的lib下的核心库类(rt.jar,charsets.jar等)

        2:拓展类加载器:加载jre的lib下的ext拓展文件中的jar包类

        3:应用程序类加载器:加载classpath下的类(自己的类)

        4:自定义类加载器:加载用户指定的类

      先来看下自定义加载器,我们如何去定义一个类加载器:

    public class Test {
    
        public void helle () {
            System.out.println("helle_classloader");
        }
    
    }

    定义一个Test类

    package com.ghsy.user.test;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    
    public class MyClassLoader extends ClassLoader {
    
        private String classPath;
    
    
        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }
    
        /**
         * 重写findClass方法
         * @param name 是我们这个类的全路径
         * @return
         * @throws ClassNotFoundException
         */
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            Class log = null;
            // 获取该class文件字节码数组
            byte[] classData = getData();
    
            if (classData != null) {
                // 将class的字节码数组转换成Class类的实例
                log = defineClass(name, classData, 0, classData.length);
            }
            return log;
        }
    
        /**
         * 将class文件转化为字节码数组
         * @return
         */
        private byte[] getData() {
    
            File file = new File(classPath);
            if (file.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(file);
                    out = new ByteArrayOutputStream();
    
                    byte[] buffer = new byte[1024];
                    int size = 0;
                    while ((size = in.read(buffer)) != -1) {
                        out.write(buffer, 0, size);
                    }
    
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        in.close();
                    } catch (IOException e) {
    
                        e.printStackTrace();
                    }
                }
                return out.toByteArray();
            }else{
                return null;
            }
    
    
        }
    
    
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException,
                InstantiationException, NoSuchMethodException, InvocationTargetException {
            MyClassLoader classLoader = new MyClassLoader("C:/test/Test.class");
            Class clazz = classLoader.findClass("com.ghsy.user.test.Test");
            Object object = clazz.newInstance();
            clazz.getMethod("helle",null).invoke(object, null);
            System.out.println(clazz.getClassLoader().getClass().getName());
        }
    
    }

    自定义一个类加载器MyClassLoader。

    我们把target下classes里面的Test.class拷贝到C盘test目录中

    控制台输出:

    D:workjavajdk1.8.0_60injava.exe "-javaagent:D:workideaIntelliJ IDEA 2018.2.5libidea_rt.jar=53557:D:workideaIntelliJ IDEA 2018.2.5in" -Dfile.encoding=UTF-8 -classpath D:workjavajdk1.8.0_60jrelibcharsets.jar;D:workjavajdk1.8.0_60jrelibdeploy.jar;D:workjavajdk1.8.0_60jrelibextaccess-bridge-64.jar;D:workjavajdk1.8.0_60jrelibextcldrdata.jar;D:workjavajdk1.8.0_60jrelibextdnsns.jar;D:workjavajdk1.8.0_60jrelibextjaccess.jar;D:workjavajdk1.8.0_60jrelibextjfxrt.jar;D:workjavajdk1.8.0_60jrelibextlocaledata.jar;D:workjavajdk1.8.0_60jrelibext
    ashorn.jar;D:workjavajdk1.8.0_60jrelibextsunec.jar;D:workjavajdk1.8.0_60jrelibextsunjce_provider.jar;D:workjavajdk1.8.0_60jrelibextsunmscapi.jar;D:workjavajdk1.8.0_60jrelibextsunpkcs11.jar;D:workjavajdk1.8.0_60jrelibextzipfs.jar;D:workjavajdk1.8.0_60jrelibjavaws.jar;D:workjavajdk1.8.0_60jrelibjce.jar;D:workjavajdk1.8.0_60jrelibjfr.jar;D:workjavajdk1.8.0_60jrelibjfxswt.jar;D:workjavajdk1.8.0_60jrelibjsse.jar;D:workjavajdk1.8.0_60jrelibmanagement-agent.jar;D:workjavajdk1.8.0_60jrelibplugin.jar;D:workjavajdk1.8.0_60jrelib
    esources.jar;D:workjavajdk1.8.0_60jrelib
    t.jar;D:workmycodecloud-parentapp-user	argetclasses;D:workjar-resourceorgspringframeworkootspring-boot-starter2.2.1.RELEASEspring-boot-starter-2.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkootspring-boot2.2.1.RELEASEspring-boot-2.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkspring-context5.2.1.RELEASEspring-context-5.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkootspring-boot-autoconfigure2.2.1.RELEASEspring-boot-autoconfigure-2.2.1.RELEASE.jar;D:workjar-resourcejakartaannotationjakarta.annotation-api1.3.5jakarta.annotation-api-1.3.5.jar;D:workjar-resourceorgspringframeworkspring-core5.2.1.RELEASEspring-core-5.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkspring-jcl5.2.1.RELEASEspring-jcl-5.2.1.RELEASE.jar;D:workjar-resourceorgyamlsnakeyaml1.25snakeyaml-1.25.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-starter-netflix-eureka-client2.2.3.RELEASEspring-cloud-starter-netflix-eureka-client-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-starter2.2.3.RELEASEspring-cloud-starter-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-context2.2.3.RELEASEspring-cloud-context-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworksecurityspring-security-crypto5.2.1.RELEASEspring-security-crypto-5.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-commons2.2.3.RELEASEspring-cloud-commons-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworksecurityspring-security-rsa1.0.9.RELEASEspring-security-rsa-1.0.9.RELEASE.jar;D:workjar-resourceorgouncycastlecpkix-jdk15on1.64cpkix-jdk15on-1.64.jar;D:workjar-resourceorgouncycastlecprov-jdk15on1.64cprov-jdk15on-1.64.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-netflix-hystrix2.2.3.RELEASEspring-cloud-netflix-hystrix-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworkootspring-boot-starter-aop2.2.1.RELEASEspring-boot-starter-aop-2.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-netflix-eureka-client2.2.3.RELEASEspring-cloud-netflix-eureka-client-2.2.3.RELEASE.jar;D:workjar-resourcecom
    etflixeurekaeureka-client1.9.21eureka-client-1.9.21.jar;D:workjar-resourceorgcodehausjettisonjettison1.3.7jettison-1.3.7.jar;D:workjar-resourcestaxstax-api1.0.1stax-api-1.0.1.jar;D:workjar-resourcecom
    etflix
    etflix-commons
    etflix-eventbus.3.0
    etflix-eventbus-0.3.0.jar;D:workjar-resourcecom
    etflix
    etflix-commons
    etflix-infix.3.0
    etflix-infix-0.3.0.jar;D:workjar-resourcecommons-jxpathcommons-jxpath1.3commons-jxpath-1.3.jar;D:workjar-resourcejoda-timejoda-time2.10.5joda-time-2.10.5.jar;D:workjar-resourceorgantlrantlr-runtime3.4antlr-runtime-3.4.jar;D:workjar-resourceorgantlrstringtemplate3.2.1stringtemplate-3.2.1.jar;D:workjar-resourceantlrantlr2.7.7antlr-2.7.7.jar;D:workjar-resourcecomgooglecodegsongson2.8.6gson-2.8.6.jar;D:workjar-resourceorgapachecommonscommons-math2.2commons-math-2.2.jar;D:workjar-resourcecom
    etflixarchaiusarchaius-core.7.6archaius-core-0.7.6.jar;D:workjar-resourcejavaxws
    sjsr311-api1.1.1jsr311-api-1.1.1.jar;D:workjar-resourcecom
    etflixservoservo-core.12.21servo-core-0.12.21.jar;D:workjar-resourcecomsunjerseyjersey-core1.19.1jersey-core-1.19.1.jar;D:workjar-resourcecomsunjerseyjersey-client1.19.1jersey-client-1.19.1.jar;D:workjar-resourcecomsunjerseycontribsjersey-apache-client41.19.1jersey-apache-client4-1.19.1.jar;D:workjar-resourceorgapachehttpcomponentshttpclient4.5.10httpclient-4.5.10.jar;D:workjar-resourceorgapachehttpcomponentshttpcore4.4.12httpcore-4.4.12.jar;D:workjar-resourcecommons-codeccommons-codec1.13commons-codec-1.13.jar;D:workjar-resourcecommons-configurationcommons-configuration1.10commons-configuration-1.10.jar;D:workjar-resourcecommons-langcommons-lang2.6commons-lang-2.6.jar;D:workjar-resourcecomgoogleinjectguice4.1.0guice-4.1.0.jar;D:workjar-resourcejavaxinjectjavax.inject1javax.inject-1.jar;D:workjar-resourceaopallianceaopalliance1.0aopalliance-1.0.jar;D:workjar-resourcecomfasterxmljacksoncorejackson-annotations2.10.0jackson-annotations-2.10.0.jar;D:workjar-resourcecomfasterxmljacksoncorejackson-core2.10.0jackson-core-2.10.0.jar;D:workjar-resourcecomfasterxmljacksoncorejackson-databind2.10.0jackson-databind-2.10.0.jar;D:workjar-resourcecomfasterxmlwoodstoxwoodstox-core5.3.0woodstox-core-5.3.0.jar;D:workjar-resourceorgcodehauswoodstoxstax2-api4.2stax2-api-4.2.jar;D:workjar-resourcecom
    etflixeurekaeureka-core1.9.21eureka-core-1.9.21.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-starter-netflix-archaius2.2.3.RELEASEspring-cloud-starter-netflix-archaius-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-netflix-archaius2.2.3.RELEASEspring-cloud-netflix-archaius-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-starter-netflix-ribbon2.2.3.RELEASEspring-cloud-starter-netflix-ribbon-2.2.3.RELEASE.jar;D:workjar-resourcecom
    etflix
    ibbon
    ibbon2.3.0
    ibbon-2.3.0.jar;D:workjar-resourcecom
    etflix
    ibbon
    ibbon-transport2.3.0
    ibbon-transport-2.3.0.jar;D:workjar-resourceio
    eactivex
    xnetty-contexts.4.9
    xnetty-contexts-0.4.9.jar;D:workjar-resourceio
    eactivex
    xnetty-servo.4.9
    xnetty-servo-0.4.9.jar;D:workjar-resourceio
    eactivex
    xnetty.4.9
    xnetty-0.4.9.jar;D:workjar-resourcecom
    etflix
    ibbon
    ibbon-core2.3.0
    ibbon-core-2.3.0.jar;D:workjar-resourcecom
    etflix
    ibbon
    ibbon-httpclient2.3.0
    ibbon-httpclient-2.3.0.jar;D:workjar-resourcecommons-collectionscommons-collections3.2.2commons-collections-3.2.2.jar;D:workjar-resourcecom
    etflix
    etflix-commons
    etflix-commons-util.3.0
    etflix-commons-util-0.3.0.jar;D:workjar-resourcecom
    etflix
    ibbon
    ibbon-loadbalancer2.3.0
    ibbon-loadbalancer-2.3.0.jar;D:workjar-resourcecom
    etflix
    etflix-commons
    etflix-statistics.1.1
    etflix-statistics-0.1.1.jar;D:workjar-resourceio
    eactivex
    xjava1.3.8
    xjava-1.3.8.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-starter-loadbalancer2.2.3.RELEASEspring-cloud-starter-loadbalancer-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-loadbalancer2.2.3.RELEASEspring-cloud-loadbalancer-2.2.3.RELEASE.jar;D:workjar-resourceioprojectreactor
    eactor-core3.3.0.RELEASE
    eactor-core-3.3.0.RELEASE.jar;D:workjar-resourceioprojectreactoraddons
    eactor-extra3.3.0.RELEASE
    eactor-extra-3.3.0.RELEASE.jar;D:workjar-resourceorgspringframeworkootspring-boot-starter-cache2.2.1.RELEASEspring-boot-starter-cache-2.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkspring-context-support5.2.1.RELEASEspring-context-support-5.2.1.RELEASE.jar;D:workjar-resourcecomstoyanrevictor1.0.0evictor-1.0.0.jar;D:workjar-resourcecom
    etflix
    ibbon
    ibbon-eureka2.3.0
    ibbon-eureka-2.3.0.jar;D:workjar-resourceorgslf4jslf4j-api1.7.29slf4j-api-1.7.29.jar;D:workjar-resourcecom	houghtworksxstreamxstream1.4.11.1xstream-1.4.11.1.jar;D:workjar-resourcexmlpullxmlpull1.1.3.1xmlpull-1.1.3.1.jar;D:workjar-resourcexpp3xpp3_min1.1.4cxpp3_min-1.1.4c.jar;D:workjar-resourceorgspringframeworkootspring-boot-starter-actuator2.2.1.RELEASEspring-boot-starter-actuator-2.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkootspring-boot-actuator-autoconfigure2.2.1.RELEASEspring-boot-actuator-autoconfigure-2.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkootspring-boot-actuator2.2.1.RELEASEspring-boot-actuator-2.2.1.RELEASE.jar;D:workjar-resourcecomfasterxmljacksondatatypejackson-datatype-jsr3102.10.0jackson-datatype-jsr310-2.10.0.jar;D:workjar-resourceiomicrometermicrometer-core1.3.1micrometer-core-1.3.1.jar;D:workjar-resourceorghdrhistogramHdrHistogram2.1.11HdrHistogram-2.1.11.jar;D:workjar-resourceorglatencyutilsLatencyUtils2.0.3LatencyUtils-2.0.3.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-starter-netflix-hystrix2.2.3.RELEASEspring-cloud-starter-netflix-hystrix-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-netflix-ribbon2.2.3.RELEASEspring-cloud-netflix-ribbon-2.2.3.RELEASE.jar;D:workjar-resourcecom
    etflixhystrixhystrix-core1.5.18hystrix-core-1.5.18.jar;D:workjar-resourcecom
    etflixhystrixhystrix-serialization1.5.18hystrix-serialization-1.5.18.jar;D:workjar-resourcecomfasterxmljacksonmodulejackson-module-afterburner2.10.0jackson-module-afterburner-2.10.0.jar;D:workjar-resourcecom
    etflixhystrixhystrix-metrics-event-stream1.5.18hystrix-metrics-event-stream-1.5.18.jar;D:workjar-resourcecom
    etflixhystrixhystrix-javanica1.5.18hystrix-javanica-1.5.18.jar;D:workjar-resourceorgapachecommonscommons-lang33.9commons-lang3-3.9.jar;D:workjar-resourceorgow2asmasm5.0.4asm-5.0.4.jar;D:workjar-resourceorgaspectjaspectjweaver1.9.4aspectjweaver-1.9.4.jar;D:workjar-resourcecomgoogleguavaguava29.0-androidguava-29.0-android.jar;D:workjar-resourcecomgoogleguavafailureaccess1.0.1failureaccess-1.0.1.jar;D:workjar-resourcecomgoogleguavalistenablefuture9999.0-empty-to-avoid-conflict-with-guavalistenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;D:workjar-resourceorgcheckerframeworkchecker-compat-qual2.5.5checker-compat-qual-2.5.5.jar;D:workjar-resourcecomgoogleerrorproneerror_prone_annotations2.3.4error_prone_annotations-2.3.4.jar;D:workjar-resourcecomgooglej2objcj2objc-annotations1.3j2objc-annotations-1.3.jar;D:workjar-resourceio
    eactivex
    xjava-reactive-streams1.2.1
    xjava-reactive-streams-1.2.1.jar;D:workjar-resourceorg
    eactivestreams
    eactive-streams1.0.3
    eactive-streams-1.0.3.jar;D:workjar-resourceorgprojectlomboklombok1.18.10lombok-1.18.10.jar;D:workjar-resourceorgspringframeworkootspring-boot-starter-log4j22.2.1.RELEASEspring-boot-starter-log4j2-2.2.1.RELEASE.jar;D:workjar-resourceorgapachelogginglog4jlog4j-slf4j-impl2.12.1log4j-slf4j-impl-2.12.1.jar;D:workjar-resourceorgapachelogginglog4jlog4j-api2.12.1log4j-api-2.12.1.jar;D:workjar-resourceorgapachelogginglog4jlog4j-core2.12.1log4j-core-2.12.1.jar;D:workjar-resourceorgapachelogginglog4jlog4j-jul2.12.1log4j-jul-2.12.1.jar;D:workjar-resourceorgslf4jjul-to-slf4j1.7.29jul-to-slf4j-1.7.29.jar;D:workmycodecloud-parentapp-user-domain	argetclasses;D:workjar-resourceorgmybatisspringootmybatis-spring-boot-starter1.3.2mybatis-spring-boot-starter-1.3.2.jar;D:workjar-resourceorgmybatisspringootmybatis-spring-boot-autoconfigure1.3.2mybatis-spring-boot-autoconfigure-1.3.2.jar;D:workjar-resourceorgmybatismybatis3.4.6mybatis-3.4.6.jar;D:workjar-resourceorgmybatismybatis-spring1.3.2mybatis-spring-1.3.2.jar;D:workjar-resourceorgspringframeworkootspring-boot-starter-jdbc2.2.1.RELEASEspring-boot-starter-jdbc-2.2.1.RELEASE.jar;D:workjar-resourcecomzaxxerHikariCP3.4.1HikariCP-3.4.1.jar;D:workjar-resourceorgspringframeworkspring-jdbc5.2.1.RELEASEspring-jdbc-5.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkspring-tx5.2.1.RELEASEspring-tx-5.2.1.RELEASE.jar;D:workjar-resourceorgmybatisgeneratormybatis-generator-core1.3.7mybatis-generator-core-1.3.7.jar;D:workjar-resourcecomalibabadruid-spring-boot-starter1.1.10druid-spring-boot-starter-1.1.10.jar;D:workjar-resourcecomalibabadruid1.1.10druid-1.1.10.jar;D:workjar-resourcemysqlmysql-connector-java8.0.18mysql-connector-java-8.0.18.jar;D:workmycodecloud-parentcloud-fegin	argetclasses;D:workjar-resourceorgspringframeworkcloudspring-cloud-starter-openfeign2.2.3.RELEASEspring-cloud-starter-openfeign-2.2.3.RELEASE.jar;D:workjar-resourceorgspringframeworkcloudspring-cloud-openfeign-core2.2.3.RELEASEspring-cloud-openfeign-core-2.2.3.RELEASE.jar;D:workjar-resourceiogithubopenfeignformfeign-form-spring3.8.0feign-form-spring-3.8.0.jar;D:workjar-resourceiogithubopenfeignformfeign-form3.8.0feign-form-3.8.0.jar;D:workjar-resourcecommons-fileuploadcommons-fileupload1.4commons-fileupload-1.4.jar;D:workjar-resourcecommons-iocommons-io2.2commons-io-2.2.jar;D:workjar-resourceiogithubopenfeignfeign-core10.10.1feign-core-10.10.1.jar;D:workjar-resourceiogithubopenfeignfeign-slf4j10.10.1feign-slf4j-10.10.1.jar;D:workjar-resourceiogithubopenfeignfeign-hystrix10.10.1feign-hystrix-10.10.1.jar;D:workjar-resourceiogithubopenfeignfeign-okhttp10.10.1feign-okhttp-10.10.1.jar;D:workjar-resourcecomsquareupokhttp3okhttp3.14.4okhttp-3.14.4.jar;D:workjar-resourcecomsquareupokiookio1.17.2okio-1.17.2.jar;D:workmycodecloud-parentapp-common	argetclasses;D:workjar-resourceorgspringframeworkootspring-boot-starter-web2.2.1.RELEASEspring-boot-starter-web-2.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkootspring-boot-starter-json2.2.1.RELEASEspring-boot-starter-json-2.2.1.RELEASE.jar;D:workjar-resourcecomfasterxmljacksondatatypejackson-datatype-jdk82.10.0jackson-datatype-jdk8-2.10.0.jar;D:workjar-resourcecomfasterxmljacksonmodulejackson-module-parameter-names2.10.0jackson-module-parameter-names-2.10.0.jar;D:workjar-resourceorgspringframeworkootspring-boot-starter-tomcat2.2.1.RELEASEspring-boot-starter-tomcat-2.2.1.RELEASE.jar;D:workjar-resourceorgapache	omcatembed	omcat-embed-core9.0.27	omcat-embed-core-9.0.27.jar;D:workjar-resourceorgapache	omcatembed	omcat-embed-el9.0.27	omcat-embed-el-9.0.27.jar;D:workjar-resourceorgapache	omcatembed	omcat-embed-websocket9.0.27	omcat-embed-websocket-9.0.27.jar;D:workjar-resourceorgspringframeworkootspring-boot-starter-validation2.2.1.RELEASEspring-boot-starter-validation-2.2.1.RELEASE.jar;D:workjar-resourcejakartavalidationjakarta.validation-api2.0.1jakarta.validation-api-2.0.1.jar;D:workjar-resourceorghibernatevalidatorhibernate-validator6.0.18.Finalhibernate-validator-6.0.18.Final.jar;D:workjar-resourceorgjbossloggingjboss-logging3.4.1.Finaljboss-logging-3.4.1.Final.jar;D:workjar-resourcecomfasterxmlclassmate1.5.1classmate-1.5.1.jar;D:workjar-resourceorgspringframeworkspring-web5.2.1.RELEASEspring-web-5.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkspring-beans5.2.1.RELEASEspring-beans-5.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkspring-webmvc5.2.1.RELEASEspring-webmvc-5.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkspring-aop5.2.1.RELEASEspring-aop-5.2.1.RELEASE.jar;D:workjar-resourceorgspringframeworkspring-expression5.2.1.RELEASEspring-expression-5.2.1.RELEASE.jar com.ghsy.user.test.MyClassLoader
    helle_classloader
    com.ghsy.user.test.MyClassLoader
    
    Process finished with exit code 0

    这个时候ClassLoader是我们自己定义的ClassLoader,不再是由AppClassLoader去加载了。

      问题1:如果自定义一个类加载器去加载?

        继承ClassLoader,重写里面的findClass方法。

      在看下这些类加载器之间的关系:

      

       自己画的一个草图,上面的null,网上由其他资料说是BootstrapClassLoader,我在jdk中并未找到明确的类(无法作证),这个启动类加载器为底层c语言实现(navtice),不需要去特意关注。

      这里提一个经常提到的概念:类加载器的双亲委派机制,下面我们来看源码(ClassLoader中的loadclass方法)

    我们先来求证一件事情,上图所对应的类加载器关系是不是这样呢?我们看AppClassLoader的源码:

    //代码【1】

    static
    class AppClassLoader extends URLClassLoader { final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);       

          //这个方法返回的是一个AppClassLoader
    public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {    //传入的为ClassLoader实现类(这里为ExtClassLoader,下面会解释) final String var1 = System.getProperty("java.class.path"); final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1); return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() { public Launcher.AppClassLoader run() { URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2); return new Launcher.AppClassLoader(var1x, var0); } }); } AppClassLoader(URL[] var1, ClassLoader var2) { super(var1, var2, Launcher.factory);    //调用父类的构造函数(看第代码【3】) this.ucp.initLookupCache(this); } public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException { int var3 = var1.lastIndexOf(46); if (var3 != -1) { SecurityManager var4 = System.getSecurityManager(); if (var4 != null) { var4.checkPackageAccess(var1.substring(0, var3)); } } if (this.ucp.knownToNotExist(var1)) { Class var5 = this.findLoadedClass(var1); if (var5 != null) { if (var2) { this.resolveClass(var5); } return var5; } else { throw new ClassNotFoundException(var1); } } else { return super.loadClass(var1, var2); } } protected PermissionCollection getPermissions(CodeSource var1) { PermissionCollection var2 = super.getPermissions(var1); var2.add(new RuntimePermission("exitVM")); return var2; } private void appendToClassPathForInstrumentation(String var1) { assert Thread.holdsLock(this); super.addURL(Launcher.getFileURL(new File(var1))); } private static AccessControlContext getContext(File[] var0) throws MalformedURLException { PathPermissions var1 = new PathPermissions(var0); ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[])null), var1); AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2}); return var3; } static { ClassLoader.registerAsParallelCapable(); } }



    //这里为LaunCh的构造方法源码(AppClassLoader和ExtClassLoader都为
    LaunCh类的内部类)
    //代码【2】
    public Launcher() {
    Launcher.ExtClassLoader var1;
    try {
    var1 = Launcher.ExtClassLoader.getExtClassLoader();    //获取了一个ExtClassLoader
    } catch (IOException var10) {
    throw new InternalError("Could not create extension class loader", var10);
    }

    try {
    this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);    //传入的是ExtClassLoader(由此证明上面AppClassLoader的getAppClassLoader方法传入的是ExtClassLoader)
        } catch (IOException var9) {
    throw new InternalError("Could not create application class loader", var9);
    }

    Thread.currentThread().setContextClassLoader(this.loader);
    String var2 = System.getProperty("java.security.manager");
    if (var2 != null) {
    SecurityManager var3 = null;
    if (!"".equals(var2) && !"default".equals(var2)) {
    try {
    var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
    } catch (IllegalAccessException var5) {
    ;
    } catch (InstantiationException var6) {
    ;
    } catch (ClassNotFoundException var7) {
    ;
    } catch (ClassCastException var8) {
    ;
    }
    } else {
    var3 = new SecurityManager();
    }

    if (var3 == null) {
    throw new InternalError("Could not create SecurityManager: " + var2);
    }

    System.setSecurityManager(var3);
    }

    }

    //
    URLClassLoader(AppClassLoader和ExtClassLoader的父类)的构造方法  在点进源码中去看,最终发现URLClassLoader是ClassLoader子类
    //代码【3】
    public URLClassLoader(URL[] urls, ClassLoader parent,
    URLStreamHandlerFactory factory) {
    super(parent);
    // this is to make the stack depth consistent with 1.1
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
    security.checkCreateClassLoader();
    }
    ucp = new URLClassPath(urls, factory);
    acc = AccessController.getContext();
    }
    
    
    //SecureClassLoader(URLClassLoader父类)中的构造方法,继续调用父类的构造方法,我们再去ClassLoader中看
    //代码【4】
    protected SecureClassLoader(ClassLoader parent) {
    super(parent);
    // this is to make the stack depth consistent with 1.1
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
    security.checkCreateClassLoader();
    }
    initialized = true;
    }

    //ClassLoader
    //代码【5】
    private ClassLoader(Void unused, ClassLoader parent) {    //这里可以看到,AppClassLoader的Parent其实已经是个ExtClssLoader的实例,
                                         //同理,ExtClassLoader都为URLClassLoader子类,这里就做过多赘述
        this.parent = parent;
    if (ParallelLoaders.isRegistered(this.getClass())) {
    parallelLockMap = new ConcurrentHashMap<>();
    package2certs = new ConcurrentHashMap<>();
    domains =
    Collections.synchronizedSet(new HashSet<ProtectionDomain>());
    assertionLock = new Object();
    } else {
    // no finer-grained lock; lock on the classloader instance
    parallelLockMap = null;
    package2certs = new Hashtable<>();
    domains = new HashSet<>();
    assertionLock = this;
    }
    }
     
    //再来看下ExtClassLoader的构造函数和getExtDirs方法,由此可证(ExtClassLoader加载的是ext扩展包中的类)
     //代码【6】
    public ExtClassLoader(File[] var1) throws IOException {
    super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);      //构造函数传入的ClassLoader是null,说明一开始执行的main函数输出String的类加载器为null是正确的,
                                                  //网上其他BootStrapClassLoader人云亦云
    SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
    }


    private static File[] getExtDirs() {
    String var0 = System.getProperty("java.ext.dirs");
    File[] var1;
    if (var0 != null) {
    StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
    int var3 = var2.countTokens();
    var1 = new File[var3];

    for(int var4 = 0; var4 < var3; ++var4) {
    var1[var4] = new File(var2.nextToken());
    }
    } else {
    var1 = new File[0];
    }

    return var1;
    }


    //最后我们来看下loadclass方发,什么情况下去调用的启动类加载器(null)
    代码【7】
    protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
    {
    synchronized (getClassLoadingLock(name)) {
    // First, check if the class has already been loaded
    Class<?> c = findLoadedClass(name);
    if (c == null) {
    long t0 = System.nanoTime();
    try {
    if (parent != null) {
    c = parent.loadClass(name, false);
    } else {
    c = findBootstrapClassOrNull(name);     //这个位置是ExtClassLoader加载器所进入到的判断(具体为啥往上翻----代码【6】,因为ExtClassLoader构造函数里面parent传入的就是null)
    }
    } catch (ClassNotFoundException e) {
    // ClassNotFoundException thrown if class not found
    // from the non-null parent class loader
    }

    if (c == null) {
    // If still not found, then invoke findClass in order
    // to find the class.
    long t1 = System.nanoTime();
    c = findClass(name);

    // this is the defining class loader; record the stats
    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
    sun.misc.PerfCounter.getFindClasses().increment();
    }
    }
    if (resolve) {
    resolveClass(c);
    }
    return c;
    }
    }
    //再来看findBootstrapClassOrNull方法
    //代码【8】
    /**
    * Returns a class loaded by the bootstrap class loader;      //返回由启动类加载器在载的Class,如果启动类无法加载,则返回null
    * or return null if not found.
    */
    private Class<?> findBootstrapClassOrNull(String name)
    {
    if (!checkName(name)) return null;

    return findBootstrapClass(name);
    }

    //findBootstrapClass方法为native方法(由c语言实现,不可见)次方法为加载jdk核心jar类的方法
    // return null if not found
    private native Class<?> findBootstrapClass(String name);
    
    

      问题1:自定义类加载器,为什么默认的parent会是AppClassLoader呢?我们来看ClassLoader的默认构造函数:

    //默认构造函数
    protected ClassLoader() {
            this(checkCreateClassLoader(), getSystemClassLoader());
        }
    
    //带有参数的构造函数,上面默认的构造函数调用了可以看到,这时候已经传入了parent,我们再来看getSystemClassLoader方法
    private ClassLoader(Void unused, ClassLoader parent) {
            this.parent = parent;
            if (ParallelLoaders.isRegistered(this.getClass())) {
                parallelLockMap = new ConcurrentHashMap<>();
                package2certs = new ConcurrentHashMap<>();
                domains =
                    Collections.synchronizedSet(new HashSet<ProtectionDomain>());
                assertionLock = new Object();
            } else {
                // no finer-grained lock; lock on the classloader instance
                parallelLockMap = null;
                package2certs = new Hashtable<>();
                domains = new HashSet<>();
                assertionLock = this;
            }
        }

    //
    getSystemClassLoader方法,调用了initSystemClassLoader方法,并且返回了scl(内部变量ClassLoader),接着来看initSystemClassLoader方法
    public static ClassLoader getSystemClassLoader() {
    initSystemClassLoader();
    if (scl == null) {
    return null;
    }
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
    checkClassLoaderPermission(scl, Reflection.getCallerClass());
    }
    return scl;
    }
    //initSystemClassLoader方法
    private static synchronized void initSystemClassLoader() {
    if (!sclSet) {
    if (scl != null)
    throw new IllegalStateException("recursive invocation");
    sun.misc.Launcher l = sun.misc.Launcher.getLauncher();      //返回了Launcher对象(包含了内部类AppClassLoader和ExtClassLoader),这个方法不过多解释,看一下就知道返回了一个LaunCher内部变量LaunCher
    if (l != null) {
    Throwable oops = null;
    scl = l.getClassLoader();      //我们再看这个getClassLoader方法,返回了内部成员CLassLoader,这个是AppClassLoader(具体为什么请看上面的Launcher类的构造函数,源码第49行)
    try {
    scl = AccessController.doPrivileged(
    new SystemClassLoaderAction(scl));
    } catch (PrivilegedActionException pae) {
    oops = pae.getCause();
    if (oops instanceof InvocationTargetException) {
    oops = oops.getCause();
    }
    }
    if (oops != null) {
    if (oops instanceof Error) {
    throw (Error) oops;
    } else {
    // wrap the exception
    throw new Error(oops);
    }
    }
    }
    sclSet = true;
    }
    }
    至此,默认的parent赋值为AppClassLoader,上面画的个个类加载器关系全部串联起来!!!!!!

      答案在上面代码中,因为默认的构造函数给parent初始化为AppClassLoader了。

      问题2:类加载器的双亲委派是怎么样实现的?

        我们还是结合源码来说:下面看ClassLoader的源码(为什么只看ClassLoader源码不在赘述,因为AppClassLoader和ExtClassLoader都执行的是ClassLoader中的laodClass方法)

    protected Class<?> loadClass(String name, boolean resolve)    //这是一个套娃过程,等会来张图解释
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);        //校验传入的类名在该类加载器中是否已经加载过了,如果加载过了,直接返回。(如果是父级加载器,也是需要判断是否加载过传入的类)
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {            //判断父级类加载器是否为空,不为空则由父级去加载此类(往上委托-----关键来了,父级也是调用次方法,再由父级去执行次方法,到ExtClassLoader这层)
                        c = parent.loadClass(name, false);   //这里开始套娃,一个个去调用父加载器,直到启动类加载器(这是个类似于递归调用)
                    } else {
                        c = findBootstrapClassOrNull(name);  //会到这里说明已经是启动类加载器了,这个时候调用本地native方法去尝试在jre核心库区加载,如果加载不到,将返回null,在打回到ExtClassLoader,一层一层往下回,直到最底层类加载器找到类为止
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
    
                if (c == null) {                                //这个位置是父级加载器没有找到类,尝试自己去加载类,这就是为什么我们自定义类加载器需要去重写这个findCLass方法
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);
    
                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

     

       这就是双亲委派机制

      问题3:为什么要使用双亲委派这个机制

        1:防止类重复加载(保证相同类只被加载一次),上面源码中已经说明。

        2:防止jdk核心jar包类被篡改,增加程序安全(这个看问题4)

      问题4:老生常谈的,我自定义一个java.lang.String会不会被加载到jvm里面去

        下面有代码来证明吧

     

       抛出异常了,String找不到main方法,明明不是有main方法吗?

      类加载机制是一个双亲委派过程,最开始是由启动类加载器去加载,启动类加载器在rt.jar中找到了java.lang.String,所以就加载了rt.jar下的String,我们自定义的String并没有被加载到jvm中。

      那么问题来了,我们自定义一个加载器能行吗?

      把上面的MyClassLoader改造一下,我们去rt.jar中找到String.class,放入到我们的test中看看呢?

       直接就抛出安全异常了,jvm不允许我们去加载以java开头包名下面的类!!!

      问题5:如何打破双亲委派机制

        这个问题我就不放代码和源码了,回头往上看讲双亲委派的那个地方,用的是loadclass方法,我们只需要自定义类加载器去继承ClassLoader类,重写里面的loadclass方法,

        不要去调用parent中的laodclass即可

      

      问题6:什么情况下去打破双亲委派机制?

        举个例子说明,我们的tomcat容器,里面由两个应用,一个是spring4版本,一个是spring5版本。如果这个时候还是双亲委派机制,那么加载了其中一个应用的spring版本,

        另一个应用spring将不会再去加载(为啥?双亲委派机制会先去校验是否已经被加载过),那么可想而知的后果是非常严重的。后面博客会讲述tomcat相关的类加载

      生而为人,我很抱歉

  • 相关阅读:
    Error: bzip2: Compressed file ends unexpectedly; # perhaps it is corrupted?
    诡异shellbash脚本没写错运行的时候不报错也不执行
    seeksv
    常用Linux对脚本的基本操作——持续更新
    lumpy-sv
    常用linux对系统的基本操作——持续更新
    常用linux对文件的基本操作——持续更新
    css浮动与定位
    CSS知识点概要
    HTML5新手入门基础知识要点概要
  • 原文地址:https://www.cnblogs.com/ghsy/p/13363073.html
Copyright © 2011-2022 走看看