Tomcat 연구 의 ClassLoader

26065 단어 ClassLoader
Tomcat 을 연구 하기 전에 기 존의 UML 도 구 를 빌려 Tomcat 의 전체적인 구 조 를 분석 하지만 Tomcat 의 절 차 를 분석 하려 면 Tomcat 의 StartUp 을 분석 하 는 데 착안 해 야 한다.Tomcat 의 시작 은 bat 파일 을 분석 하 는 것 부터 시작 합 니 다. bat 파일 은 최종 적 으로 org. apache. catalina. startup. bootstrap 을 호출 하여 클래스 를 불 러 옵 니 다.
1. Tomcat 의 ClassLoader:
    TOMCAT 자체 클래스 로 더 (ClassLoader)
       +---------------------------+
       |         Bootstrap         |
       |             |             |
       |          System           |
       |             |             |
       |          Common           |
       |         /      /          |
       |     Catalina  Shared      |
       +---------------------------+
     그 중:
- Bootstrap - JVM 자체 클래스 와 $JAVA 불 러 오기HOME/jre/lib/ext/*.jar
     - System   
  • $CATALINA 불 러 오기HOME/bin/bootstrap.jar  Tomcat 초기 화, 메 인 방법 실행
  • $JAVA_HOME/lib/tools.jar  Sun 의 도구 클래스, JSp 를 Servlet 로 컴 파일 하 는 도구 클래스 포함
  •     - Common               이 디 렉 터 리 에 있 는 클래스 는 TOMCAT 와 모든 WEB 앱 을 볼 수 있 습 니 다. 하지만 웹 앱 의 클래스 는 이 디 렉 터 리 에 두 지 말 아야 합 니 다. 포장 되 지 않 은 모든 Class 는 $CATALINA 에 있 습 니 다.HOME / common / classes 아래 모든 포 장 된 jar 는 $CATALINAHOME / commons / endorsed 와 $CATALINAHOME / common / lib 에서 기본 적 인 상황 은 다음 과 같은 몇 개의 가방 을 포함 합 니 다.
                        1. jndi. jar JNDI API 인터페이스, 이 패 키 지 는 자바 1.2 시 에 만 불 러 옵 니 다. 1.3 이후 버 전 JDK 는 자동 으로 불 러 옵 니 다.
                        2. naming - common. jar JNDI 인터페이스 구현 클래스, Tomcat 은 이러한 클래스 로 메모리 에 Context 를 사용 합 니 다.
                        3. naming - resources. jar JNDI 구현, Tomcat 는 웹 앱 의 정적 자원 을 찾 습 니 다.
                        4. servlet.jar Servlet,Jsp API
                        5. xerces. jar XML 해상도 기, 특정 웹 앱 은 자신의 / WEB - INF / lib 에 덮어 쓸 수 있 습 니 다.
        - Catalina           Tomcat 를 불 러 와 모든 인 터 페 이 스 를 실현 하 는 클래스 입 니 다. 이러한 클래스 는 웹 앱 에 전혀 보이 지 않 습 니 다. 모든 패키지 되 지 않 은 클래스 는 $CATALINA 에 있 습 니 다.HOME / server / classes 모든 jar 가방 $CATALINAHOME / server / lib 아래 에 있 습 니 다. 일반적인 상황 에서 이 ClassLoader 는 아래 의 몇 개의 가방 을 로드 합 니 다.
                        1. catalina. jar Servlet 용기 의 Tomcat 구현 패키지
                        2. jakarta - regexp - X. Y. jar 정규 표현 식, 필터 요청 시 사용
                        3. servlets - xxxx. jar Servlet 지원 패키지
                        4. tomcat - coyote. jar Tomcat 의 Coyote 연결 실현 패키지
                        5. tomcat - jk. jar 웹 서버 바 인 딩 패키지, Tomcat 바 인 딩 아파 치 등 을 웹 서버 로 허용
                        6. tomcat - jk2. jar 기능 동일
                        7. tomcat - util. jar Tomcat 도구 류, 일부 커 넥 터 에 사 용 될 수 있 습 니 다.
                        8. tomcat - warp. jar 는 아파 치 서버 패키지 에 사용
         - Shared   모든 WEB APP 에서 볼 수 있 는 클래스 를 불 러 옵 니 다. TOMCAT 에 서 는 볼 수 없습니다.
                        $CATALINA_HOME / shared / classes 모든 jar 가방 $CATALINAHOME / lib 아래.
                        기본 상황 은 다음 가방 을 포함 합 니 다:
                        1. jasper - copiler. jar Jsp 컴 파일 러, Jsp 를 Servlet 로 컴 파일
                        2. jasper - runtime. jar JSp (Servlet 로 컴 파일 됨) 실행 지원 패키지
                        3. naming - factory. jar 는 웹 앱 이 JNDI 패 키 지 를 사용 하 는 것 을 지원 합 니 다.
         -WebAppX   웹 앱 ClassLoader, 웹 앱 이 배 치 될 때 이 ClassLoader 가 생 성 됩 니 다. 모든 class 가 있 습 니 다.
                        WEB - INF / classes 에서 모든 jar 는 WEB - INF / lib 아래 에 있 습 니 다.
      
      특히 WEB APP 자체 의 ClassLoader 구현 이 남 다 르 므 로 주의 하 시기 바 랍 니 다.
      먼저 WEB APP 자신의 디 렉 터 리 에서 불 러 오 려 고 합 니 다. 실패 하면 부모 ClassLoader 의 프 록 시 를 요청 합 니 다. 그러면 서로 다른 WEB APP 간 의 클래스 를 불 러 오 는 데 방해 가 되 지 않 습 니 다. 또한 Tomcat Server 는 CatalinaClassLoader, 일반적인 웹 앱 에서 사용 하 는 WebApp ClassLoader 를 사용 합 니 다.
    2. org. apache. catalina. startup. bootstrap
     이 종 류 는 Tomcat 의 집행 입구 점 입 니 다. 우 리 는 다음 과 같은 두 가지 방법 을 중점적으로 분석 합 니 다.
    2.1. initClassLoaders, ClassLoader 차원 만 들 기
    private void initClassLoaders() {
    
                    try {
    
                              ClassLoaderFactory.setDebug(debug);
    
                              //  common ClassLoader,   ClassLoader
    
                              commonLoader = createClassLoader("common", null);
    
     
    
                              //  catalina ClassLoader, ClassLoader common
    
                              catalinaLoader = createClassLoader("server",commonLoader);
    
     
    
                              //  shared ClassLoader,  ClassLoader common
    
                              sharedLoader = createClassLoader("shared",commonLoader);
    
                         } catch (Throwable t) {
    
                              log("Class loader creation threw exception", t);
    
                              System.exit(1);
    
                         }
    
                 }
    
    

       2.2 createClassLoader, 구체 적 인 창설 담당
    $CATALINAHOME / conf / catalina. properties 에 서 는 common, server, shared ClassLoader 가 불 러 오 는 경로 와 가방 의 보안 권한 을 정의 합 니 다.
     //common      
    
      common.loader=${catalina.home}/common/classes,
    
                ${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar
    
                //server      
    
                server.loader=${catalina.home}/server/classes,${catalina.home}/server/lib/*.jar
    
     
    
                //shared      
    
                shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar
    
             
    
            /**
    
              *param name:Load Name
    
              *param parent: Loader
    
              *classLoader      :
    
              *1.    classes,       
    
              *2.   jar  
    
              *3.    ,        jar  (Applet       loader)
    
              */
    
            private ClassLoader createClassLoader(String name, ClassLoader parent)
    
                        throws Exception {
    
     
    
              // catalina.properties    Loader     
    
              String value = CatalinaProperties.getProperty(name + ".loader");
    
              if ((value == null) || (value.equals("")))
    
                        return parent;
    
             
    
              //classes  
    
          ArrayList unpackedList = new ArrayList();
    
              //jar  
    
          ArrayList packedList = new ArrayList();
    
              //        
    
          ArrayList urlList = new ArrayList();
    
     
    
               StringTokenizer tokenizer = new StringTokenizer(value, ",");
    
                
    
                 //  Loader     
    
                 while (tokenizer.hasMoreElements()) {
    
                        String repository = tokenizer.nextToken();
    
                        // Check for a JAR URL repository
    
                try {
    
                    //         url
    
                    urlList.add(new URL(repository));
    
                    continue;
    
                } catch (MalformedURLException e) {
    
                    // Ignore
    
                }
    
     
    
                //     
    
                boolean packed = false;
    
     
    
               //${catalina.home}
    
                if (repository.startsWith(CATALINA_HOME_TOKEN)) {
    
                    repository = getCatalinaHome()
    
                        + repository.substring(CATALINA_HOME_TOKEN.length());
    
               //${catalina.base}
    
               } else if (repository.startsWith(CATALINA_BASE_TOKEN)) {
    
                    repository = getCatalinaBase()
    
                        + repository.substring(CATALINA_BASE_TOKEN.length());
    
                        }
    
                        /**      , catalina.properties           */
    
               
    
               //   jar    
    
               if (repository.endsWith("*.jar")) {
    
                    packed = true;
    
                    repository = repository.substring
    
                        (0, repository.length() - "*.jar".length());
    
                }
    
                if (packed) {
    
                    packedList.add(new File(repository));
    
                } else {
    
                    unpackedList.add(new File(repository));
    
                }
    
            }
    
     
    
            File[] unpacked = (File[]) unpackedList.toArray(new File[0]);
    
            File[] packed = (File[]) packedList.toArray(new File[0]);
    
            URL[] urls = (URL[]) urlList.toArray(new URL[0]);
    
     
    
            //  Factory     ClassLoader
    
            return ClassLoaderFactory.createClassLoader
    
                (unpacked, packed, urls, parent);
    
        }
    
    

    3. ClassLoaderFactory
    ClassLoader Factory 는 ClassLoader 를 만 드 는 공장 류 로 간단 합 니 다.
    //        ,       
    
    public static ClassLoader createClassLoader(File unpacked[],
    
                                                    File packed[],
    
                                                    URL urls[],
    
                                                    ClassLoader parent)
    
            throws Exception {
    
     
    
            if (debug >= 1)
    
                log("Creating new class loader");
    
     
    
            // Construct the "class path" for this class loader
    
            ArrayList list = new ArrayList();
    
     
    
            //   class    file   url,    list
    
            if (unpacked != null) {
    
                for (int i = 0; i < unpacked.length; i++)  {
    
                    File file = unpacked[i];
    
                    if (!file.exists() || !file.canRead())
    
                        continue;
    
                    if (debug >= 1)
    
                        log("  Including directory or JAR "
    
                            + file.getAbsolutePath());
    
                    URL url = new URL("file", null,
    
                                      file.getCanonicalPath() + File.separator);
    
                    list.add(url.toString());
    
                }
    
            }
    
     
    
            //    jar    jar  ,    url,    list
    
            if (packed != null) {
    
                for (int i = 0; i < packed.length; i++) {
    
                    File directory = packed[i];
    
                    if (!directory.isDirectory() || !directory.exists() ||
    
                        !directory.canRead())
    
                        continue;
    
                    String filenames[] = directory.list();
    
                    for (int j = 0; j < filenames.length; j++) {
    
                        String filename = filenames[j].toLowerCase();
    
                        if (!filename.endsWith(".jar"))
    
                            continue;
    
                        File file = new File(directory, filenames[j]);
    
                        if (debug >= 1)
    
                            log("  Including jar file " + file.getAbsolutePath());
    
                        URL url = new URL("file", null,
    
                                          file.getCanonicalPath());
    
                        list.add(url.toString());
    
                    }
    
                }
    
            }
    
     
    
            //         
    
            if (urls != null) {
    
                for (int i = 0; i < urls.length; i++) {
    
                    list.add(urls[i].toString());
    
                }
    
            }
    
     
    
            //  StandardClassLoader     Loader
    
            String array[] = (String[]) list.toArray(new String[list.size()]);
    
            StandardClassLoader classLoader = null;
    
            if (parent == null)
    
                classLoader = new StandardClassLoader(array);
    
            else
    
                classLoader = new StandardClassLoader(array, parent);
    
            classLoader.setDelegate(true);
    
            return (classLoader);
    
     
    
        }
    
    

    4. 표준 클래스 로 더
       Standard ClassLoader 는 URLClassLoader 를 계승 합 니 다. URLClassLoader 류 는 하 드 디스크 디 렉 터 리 에서 클래스 를 불 러 오 거나 로 컬 또는 원 격 으로 jar 파일 을 불 러 오 는 능력 을 가지 고 있 습 니 다. 이 클래스 는 Reloader 인 터 페 이 스 를 실현 하여 자동 으로 클래스 를 다시 불 러 오 는 기능 을 제공 합 니 다. 우 리 는 주로 이 클래스 의 아래 와 방법 을 봅 니 다.
    4.1. 구조 함수 표준 ClassLoader
    /**
    
         * @param repositories url  ,    
    
         * @param parent  loader
    
         */
    
        public StandardClassLoader(String repositories[], ClassLoader parent) {
    
           //         
    
           //             repositories  URLClassPath   
    
           //ucp      ucp= new URLClassPath(urls);
    
          // URLClassPath sun    ,      
    
            super(convert(repositories), parent);
    
            this.parent = parent;
    
            this.system = getSystemClassLoader();
    
            securityManager = System.getSecurityManager();
    
         if (repositories != null) {
    
                for (int i = 0; i < repositories.length; i++)
    
                    //  url
    
                    addRepositoryInternal(repositories[i]);
    
            }
    
        }
    
    

      4.2 addRepositoryInternal
    /**
    
         * @param repository     url
    
         */
    
        protected void addRepositoryInternal(String repository) {
    
     
    
            URLStreamHandler streamHandler = null;
    
            String protocol = parseProtocol(repository);
    
            if (factory != null)
    
                streamHandler = factory.createURLStreamHandler(protocol);
    
     
    
            //   url         jar  ,  jar    
    
            //               jar      ,  jar           .
    
            if (!repository.endsWith(File.separator) && !repository.endsWith("/")) {
    
                JarFile jarFile = null;
    
                try {
    
                    Manifest manifest = null;
    
     
    
                    //jar  
    
                    if (repository.startsWith("jar:")) {
    
                        URL url = new URL(null, repository, streamHandler);
    
                        JarURLConnection conn =
    
                            (JarURLConnection) url.openConnection();
    
                        conn.setAllowUserInteraction(false);
    
                        conn.setDoInput(true);
    
                        conn.setDoOutput(false);
    
                        conn.connect();
    
                        jarFile = conn.getJarFile();
    
                   
    
                    //file  
    
                    } else if (repository.startsWith("file://")) {
    
                        jarFile = new JarFile(repository.substring(7));
    
                    //file
    
                    } else if (repository.startsWith("file:")) {
    
                        jarFile = new JarFile(repository.substring(5));
    
     
    
                    //     jar  
    
                    } else if (repository.endsWith(".jar")) {
    
                        URL url = new URL(null, repository, streamHandler);
    
                        URLConnection conn = url.openConnection();
    
                        JarInputStream jis =
    
                            new JarInputStream(conn.getInputStream());
    
                        manifest = jis.getManifest();
    
     
    
                    //        
    
                    } else {
    
                        throw new IllegalArgumentException
    
                            ("addRepositoryInternal:  Invalid URL '" +
    
                             repository + "'");
    
                    }
    
                } catch (Throwable t) {
    
                    t.printStackTrace();
    
                    throw new IllegalArgumentException
    
                        ("addRepositoryInternal: " + t);
    
                } finally {
    
                    if (jarFile != null) {
    
                        try {
    
                            jarFile.close();
    
                        } catch (Throwable t) {}
    
                    }
    
                }
    
            }
    
     
    
            //     url      url  
    
            synchronized (repositories) {
    
                String results[] = new String[repositories.length + 1];
    
                System.arraycopy(repositories, 0, results, 0, repositories.length);
    
                results[repositories.length] = repository;
    
                repositories = results;
    
            }
    
        }
    
    

    reposcories 는 모든 url 목록 을 저장 하 는 클래스 변수 입 니 다.
    이 방법 을 통 해 우 리 는 기본적으로 몇 가 지 를 확정 할 수 있다.
    1. ClassLoader 는 '/' 또는 File. separator 로 끝 나 는 경 로 를 불 러 오 는 자원 으로 할 수 있 습 니 다.
    2. 로 컬 이나 네트워크 에 있 는 jar 파일 을 class 를 불 러 오 는 자원 으로 할 수도 있 습 니 다. 다른 모든 형식의 자원 (예 를 들 어 zip) 은 합 법 적 이지 않 습 니 다.
    3. 네트워크 의 자원 은 jar 패키지 형식 이 어야 합 니 다.
    여기까지, ClassLoader 의 구조 가 끝 났 습 니 다.
      4.3 loadclass 방법
    위 에서 우 리 는 많은 일 을 했 습 니 다. 그 목적 은 classLoader 를 구축 하 는 것 입 니 다. ClassLoader 를 구축 하 는 목적 은 그것 으로 원 하 는 class 를 로드 하 는 것 입 니 다. 따라서 loadClass 방법 이 우리 의 중심 이 고 이 를 통 해 ClassLoader 의 신비 한 베일 을 철저히 풀 수 있 습 니 다.
    /**
    
          *param name: load   
    
          *param resolve:   true   resolveClass
    
         */
    
        public Class loadClass(String name, boolean resolve)
    
            throws ClassNotFoundException {
    
     
    
            if (debug >= 2)
    
                log("loadClass(" + name + ", " + resolve + ")");
    
            Class clazz = null;
    
     
    
            //    ,       load
    
            clazz = findLoadedClass(name);
    
            if (clazz != null) {
    
                if (debug >= 3)
    
                    log("  Returning class from cache");
    
                if (resolve)
    
                    resolveClass(clazz);
    
                return (clazz);
    
            }
    
     
    
            //    java    ClassLoader load
    
            if( name.startsWith("java.") ) {
    
                ClassLoader loader = system;
    
                clazz = loader.loadClass(name);
    
                if (clazz != null) {
    
                    if (resolve)
    
                        resolveClass(clazz);
    
                    return (clazz);
    
                }
    
                throw new ClassNotFoundException(name);
    
            }
    
     
    
            //                load,  load   catalina.properties   
    
            if (securityManager != null) {
    
                int i = name.lastIndexOf('.');
    
                if (i >= 0) {
    
                    try {
    
                        securityManager.checkPackageAccess(name.substring(0,i));
    
                    } catch (SecurityException se) {
    
                        String error = "Security Violation, attempt to use " +
    
                            "Restricted Class: " + name;
    
                        System.out.println(error);
    
                        se.printStackTrace();
    
                        log(error);
    
                        throw new ClassNotFoundException(error);
    
                    }
    
                }
    
            }
    
     
    
            //        ClassLoader   
    
            if (delegate) {
    
                if (debug >= 3)
    
                    log("  Delegating to parent classloader");
    
                ClassLoader loader = parent;
    
                if (loader == null)
    
                    loader = system;
    
                try {
    
                    clazz = loader.loadClass(name);
    
                    if (clazz != null) {
    
                        if (debug >= 3)
    
                            log("  Loading class from parent");
    
                        if (resolve)
    
                            resolveClass(clazz);
    
                        return (clazz);
    
                    }
    
                } catch (ClassNotFoundException e) {
    
                    ;
    
                }
    
            }
    
     
    
            //       
    
            if (debug >= 3)
    
                log("  Searching local repositories");
    
            try {
    
               //  Tomcat  ClassLoader         
    
                clazz = findClass(name);
    
                if (clazz != null) {
    
                    if (debug >= 3)
    
                        log("  Loading class from local repository");
    
                    if (resolve)
    
                        resolveClass(clazz);
    
                    return (clazz);
    
                }
    
            } catch (ClassNotFoundException e) {
    
                ;
    
            }
    
     
    
            //            ,    loader   
    
                if (debug >= 3)
    
                    log("  Delegating to parent classloader");
    
                ClassLoader loader = parent;
    
                if (loader == null)
    
                    loader = system;
    
                try {
    
                    clazz = loader.loadClass(name);
    
                    if (clazz != null) {
    
                        if (debug >= 3)
    
                            log("  Loading class from parent");
    
                        if (resolve)
    
                            resolveClass(clazz);
    
                        return (clazz);
    
                    }
    
                } catch (ClassNotFoundException e) {
    
                    ;
    
                }
    
            }
    
     
    
            // This class was not found
    
            throw new ClassNotFoundException(name);
    
     
    
        }
    
    

      4.4 findClass 방법
    public Class findClass(String name) throws ClassNotFoundException {
    
     
    
            if (debug >= 3)
    
                log("    findClass(" + name + ")");
    
     
    
            //       ,            
    
            if (securityManager != null) {
    
                int i = name.lastIndexOf('.');
    
                if (i >= 0) {
    
                    try {
    
                        if (debug >= 4)
    
                            log("      securityManager.checkPackageDefinition");
    
                        securityManager.checkPackageDefinition(name.substring(0,i));
    
                    } catch (Exception se) {
    
                        if (debug >= 4)
    
                            log("      -->Exception-->ClassNotFoundException", se);
    
                        throw new ClassNotFoundException(name);
    
                    }
    
                }
    
            }
    
            //                  
    
            // (throws ClassNotFoundException if it is not found)
    
            Class clazz = null;
    
            try {
    
                if (debug >= 4)
    
                    log("      super.findClass(" + name + ")");
    
                try {
    
                    synchronized (this) {                             
    
                        clazz = findLoadedClass(name);
    
                        if (clazz != null)
    
                            return clazz;
    
                       //      
    
                        clazz = super.findClass(name);
    
                    }
    
                } catch(AccessControlException ace) {
    
                    throw new ClassNotFoundException(name);
    
                } catch (RuntimeException e) {
    
                    if (debug >= 4)
    
                        log("      -->RuntimeException Rethrown", e);
    
                    throw e;
    
                }
    
                if (clazz == null) {
    
                    if (debug >= 3)
    
                        log("    --> Returning ClassNotFoundException");
    
                    throw new ClassNotFoundException(name);
    
                }
    
            } catch (ClassNotFoundException e) {
    
                if (debug >= 3)
    
                    log("    --> Passing on ClassNotFoundException", e);
    
                throw e;
    
            }
    
            // Return the class we have located
    
            if (debug >= 4)
    
                log("      Returning class " + clazz);
    
            if ((debug >= 4) && (clazz != null))
    
                log("      Loaded by " + clazz.getClassLoader());
    
            return (clazz);
    
     
    
        }
    
    

      4.5 부모 클래스 (URLClassLoader) 의 findClass 방법
    앞에서 말 했 듯 이 URLClassLoader 는 로 컬 에서 class 를 불 러 오고 로 컬 이나 네트워크 에서 jar 를 불 러 오 는 기능 을 가지 고 있 습 니 다.
    쉽게 말 하면 findClass 방법 은 Privileged ExceptionAction 의 run 방법 을 간단하게 호출 했 을 뿐 입 니 다. 이런 유형 에 대해 서 는 자세히 알 필요 가 없습니다. 아래 에 파란색 을 치 는 부분 만 보면 됩 니 다.
    protected Class findClass(final String name) throws ClassNotFoundException  {
    
          try {
    
              return (Class)
    
                    AccessController.doPrivileged(new PrivilegedExceptionAction() {
    
                        public Object run() throws ClassNotFoundException {
    
                               //            
    
                               String path = name.replace('.', '/').concat(".class");
    
                               //  ucp         
    
                               //          class     Resource(       )
    
                               Resource res = ucp.getResource(path, false);
    
                               if (res != null) {
    
                                   try {
    
                                         //       Resource  Class
    
                                         return defineClass(name, res);
    
                                   } catch (IOException e) {
    
                                         throw new ClassNotFoundException(name, e);
    
                                   }
    
                               } else {
    
                                   throw new ClassNotFoundException(name);
    
                               }
    
                        }
    
                    }, acc);
    
          } catch (java.security.PrivilegedActionException pae) {
    
              throw (ClassNotFoundException) pae.getException();
    
          }
    
        }
    
    

      4.6 define Class 방법
    이 방법 은 주로 JVM 의 native 방법 으로 class 대상 을 구축 하 는 것 입 니 다. 이러한 세부 사항 에 대해 서 는 제거 할 필요 가 없습니다. JVM 이 Resource 를 이용 하여 Class 대상 을 구 조 했 습 니 다. 아래 파란색 부분 만 주목 하 십시오.
     /**
    
            *param name:  
    
            *param res:       ucp    ,ucp        url  ,url  
    
            *ClassLoader Load Class    
    
            *           StandClassLoader      Resource
    
            *Resource JVM    Class    
    
            */
    
        private Class defineClass(String name, Resource res) throws IOException {
    
          int i = name.lastIndexOf('.');
    
          URL url = res.getCodeSourceURL();
    
          if (i != -1) {
    
              String pkgname = name.substring(0, i);
    
              // Check if package already loaded.
    
              Package pkg = getPackage(pkgname);
    
              Manifest man = res.getManifest();
    
              if (pkg != null) {
    
                    // Package found, so check package sealing.
    
                    if (pkg.isSealed()) {
    
                        // Verify that code source URL is the same.
    
                        if (!pkg.isSealed(url)) {
    
                               throw new SecurityException(
    
                                   "sealing violation: package " + pkgname + " is sealed");
    
                        }
    
     
    
                    } else {
    
                        // Make sure we are not attempting to seal the package
    
                        // at this code source URL.
    
                        if ((man != null) && isSealed(pkgname, man)) {
    
                               throw new SecurityException(
    
                                   "sealing violation: can't seal package " + pkgname +
    
                                   ": already loaded");
    
                        }
    
                    }
    
              } else {
    
                    if (man != null) {
    
                        definePackage(pkgname, man, url);
    
                    } else {
    
                        definePackage(pkgname, null, null, null, null, null, null, null);
    
                    }
    
              }
    
          }
    
          //   JVM           Class
    
          byte[] b = res.getBytes();
    
          java.security.cert.Certificate[] certs = res.getCertificates();
    
          CodeSource cs = new CodeSource(url, certs);
    
          return defineClass(name, b, 0, b.length, cs);
    
        }
    
    

    이로써 우 리 는 Tomcat 의 ClassLoader 를 철저히 파 역 했 습 니 다. 다음은 ClassLoader 의 구조 와 loadClass 의 과정 을 다시 그 려 보 겠 습 니 다. 여 기 는 sequence 그림 을 그리 지 않 고 각 방법 간 의 호출 관 계 를 간단하게 표시 할 뿐 입 니 다.
    사실 위 에서 우리 가 진정 으로 ClassLoader 를 만 드 는 관건 적 인 역할 을 할 수 있 는 것 은 URLClassLoader 와 JVM 의 defineClass 방법 입 니 다. 이런 방법 들 은 이미 봉인 되 었 거나 로 컬 호출 되 었 기 때문에 더 연구 하려 면 더 많은 정력 을 들 여야 합 니 다. 이 절 차 를 읽 은 후에 모든 사람 이 자신 이 필요 로 하 는 ClassLoader, 예 를 들 어 암호 화 ClassLoader 등 을 맞 출 수 있 을 것 이 라 고 믿 습 니 다.

    좋은 웹페이지 즐겨찾기